2013-03-04 24 views
11

C++11 cung cấp user-defined literals. Tôi vừa mới bắt đầu chơi với họ, điều đó khiến tôi tự hỏi liệu có thể tự động thêm tất cả SI multipliers vào một chữ mà tôi định nghĩa không?Làm cách nào để tự động thêm định nghĩa theo nghĩa đen, dựa trên một chữ cái do người dùng xác định?

Ví dụ, nếu tôi xác định

Length operator "" _m(long double m) { 
    return Length(m); // Length in meters 
} 

nơi Length là một lớp con của một số lớp Units cơ sở, tôi muốn có một cơ chế để tự động add (theo tinh thần giống như boost operators) nhân SI cho tất cả các chữ mà trả về một Length:

// these are added automatically when defining the literal "_m": 
             // Length in: 
Length operator "" _Ym(long double Ym); // Yottameters 
Length operator "" _Zm(long double Zm); // Zetameters 
...          // ... 
...          // ... 
Length operator "" _km(long double km); // kilometers 
Length operator "" _mm(long double mm); // millimeters 
...          // ...  
...          // ... 
Length operator "" _zm(long double zm); // zeptometers 
Length operator "" _ym(long double ym); // yoctometers 

theo như tôi có thể thấy, ngoài việc có lẽ một số ma thuật vĩ mô, không có cách nào để làm một này tự động vì tất cả các chữ cái do người dùng xác định cần định nghĩa rõ ràng.

.. tôi có đang xem cái gì đó không?

+0

Tại sao không phải với mẫu? –

+0

@Adriano: ví dụ? –

+0

Tương tự như này: http://www.codeproject.com/Articles/447922/Application-of-Cplusplus11-User-Defined-Literals-t (nếu bạn có thể bỏ qua các đơn vị đo lường phần và giữ nhân chỉ ... Tôi bỏ lỡ điểm đó, bạn nói đúng, chúng tôi có thể cần _macro magic_) –

Trả lời

3

Tôi không nghĩ rằng có một cách để làm chính xác những gì bạn đang yêu cầu mà không cần "macro kỳ quái". Đây là như xa như tôi có thể nhận được:

template<typename T, T (*op)(long double)> 
struct SI 
{ 
    // ... 
    constexpr static T micro = op (.000001); 
    constexpr static T milli = op (.001); 
    constexpr static T kilo = op (1000); 
    constexpr static T mega = op (1000000); 
    // ... 
}; 

struct Length 
{ 
    constexpr Length(long double d) : _d(d) { } 
    constexpr operator long double() { return _d; } 
    long double _d; 
}; 

constexpr Length operator "" _m(long double m) { 
    return Length(m); 
} 

typedef SI<Length, ::operator "" _m> SI_Length; 

int main() 
{ 
    constexpr Length l = 3 * SI_Length::kilo; 
    static_assert(l == 3000, "error"); 
} 

Nếu macro kỳ lạ được cho phép, sau đó một cái gì đó như sau nên thực hiện công việc:

#define DEFINE_SI_MULTIPLIERS(T, unit) \ 
    constexpr T operator "" _u ## unit(long double m) \ 
    { return ::operator "" _ ## unit(0.000001 * m); } \ 
    constexpr T operator "" _m ## unit(long double m) \ 
    { return ::operator "" _ ## unit(0.001 * m); } \ 
    constexpr T operator "" _k ## unit(long double m) \ 
    { return ::operator "" _ ## unit(1000 * m); } \ 
    // ... 

DEFINE_SI_MULTIPLIERS(Length, m) 

int main() 
{ 
    constexpr Length l = 3.0_km; 
    static_assert(l == 3000, "error"); 
} 
+1

hmm ... đẹp nỗ lực (+1), nhưng điều này sẽ không khác nhiều so với chỉ đơn giản là nhân với 'yếu tố const' SI định nghĩa trong một không gian tên (ví dụ,' Chiều dài L = 3 * si :: kg; '); IMHO nó không thêm nhiều sức mạnh biểu cảm ... –

+0

@RodyOldenhuis: True. Như tôi đã đề cập, điều này chỉ là xa như tôi có thể nhận được, và đó có lẽ không phải là rất xa. Tôi tin rằng các macro là cách duy nhất để đạt được những gì bạn đang tìm kiếm. –

+0

Tôi cũng tin như vậy. Đã chấp nhận! –

-1

bạn không thể sử dụng các hương vị operator "" _m(const char *) miễn là bạn sẵn sàng để phân tích nổi chính mình? Điều đó làm cho nó có thể viết 1234k_m bằng cách gọi ra một phân tích cú pháp SI-aware chung cho các giá trị dấu chấm động của bạn.

+2

Bạn có phải là điều này có nghĩa vụ phải làm việc? Sử dụng gcc 4.7.2 này được phân tách thành '1234'' k_m' và gcc tìm kiếm toán tử '" "k_m', xem [liveworkspace] (http://liveworkspace.org/code/1YjxLZ$0). –