2016-09-30 34 views
7

On cppreference có một đề cập rằng người ta có thể có nhà khai thác sử dụng theo nghĩa đen templated, với một số hạn chế:Khi nào và làm thế nào để sử dụng toán tử mẫu?

Nếu các nhà điều hành nghĩa đen là một mẫu, nó phải có một danh sách tham số rỗng và có thể chỉ có một tham số mẫu, mà phải là một tổ chức phi kiểu mẫu tham số gói với yếu tố loại char, chẳng hạn như

template <char...> double operator "" _x(); 

vì vậy, tôi đã viết một mặt hàng như trong các mã dưới đây:

template <char...> 
double operator "" _x() 
{ 
    return .42; 
} 

int main() 
{ 
    10_x; // empty template list, how to specify non-empty template parameters? 
} 

Câu hỏi:

  1. Mã này hoạt động, nhưng làm thế nào tôi có thể sử dụng toán tử với một số thông số mẫu không có sản phẩm nào? 10_x<'a'>; hoặc 10_<'a'>x; không biên dịch.
  2. Bạn có ví dụ nào về việc sử dụng thực tế các nhà khai thác templated như thế giới thực không?
+1

Tôi chưa bao giờ thấy điều đó trước đây, nhưng có vẻ như ý tưởng là xử lý các ký tự trước tiền tố dưới dạng 'char' tại thời gian biên dịch, chứ không phải xử lý nó như một chữ số và truyền nó đến một run- chức năng thời gian. –

+0

@KyleStrand Nhưng tôi vẫn không chắc chắn cách bạn sử dụng nó (tức là biên dịch nó không có lỗi). – vsoftco

+0

Rõ ràng là tôi không phải là, vì tôi chưa bao giờ thấy nó trước đây! Nhưng tôi có một ví dụ làm việc mà tôi vừa viết, vì vậy tôi sẽ đăng nó. –

Trả lời

7
10_x; // empty template list, how to specify non-empty template parameters? 

Đó không phải là hoàn toàn đúng. Danh sách tham số mẫu không trống. Khi bạn viết:

template <char... Cs> 
??? operator "" _x() 

Cs được điền từ nội dung ở phía bên trái của chữ. Đó là, khi bạn viết:

10_x 

mà các cuộc gọi:

operator ""_x<'1', '0'>(); 

Một ví dụ đơn giản sẽ là xây dựng một thời gian biên dịch, tràn an toàn nhị phân đen như vậy:

template <uint64_t V> 
constexpr uint64_t make_binary() { 
    return V; 
} 

template <uint64_t V, char C, char... Cs> 
constexpr uint64_t make_binary() { 
    static_assert(C == '0' || C == '1', "invalid binary"); 

    return make_binary<2*V + C - '0', Cs...>(); 
} 

template <char... Cs> 
uint64_t operator "" _b() 
{ 
    static_assert(sizeof...(Cs) <= 64, "overflow"); 

    return make_binary<0, Cs...>(); 
} 

uint64_t a = 101_b; // OK: a == 5 
uint64_t b = 102_b; // error: invalid 
uint64_t c = 11111111110000000000111111111100000000001111111111000000000011111111110000000000_b; // error: overflow 
+0

Ohhh Tôi hiểu, vâng, có ý nghĩa hoàn hảo, vì chính nhà điều hành không có đối số ... Nhưng có vẻ như hoàn toàn không có cách nào để truy cập vào 'char' đó. – vsoftco

+2

@vsoftco Ý của bạn là gì? Chúng giống như bất kỳ tham số không kiểu nào khác. – Barry

+0

Tôi có nghĩa là họ không có tên, vì vậy tôi không thể kéo chúng ra trực tiếp bên trong nhà điều hành. Nhưng ví dụ của @ Kyle làm rõ nó một chút. Ok, bây giờ tôi thấy nhiều kịch bản hơn trong các bình luận, tôi nhận ra bạn có thể đặt tên cho chúng. – vsoftco

3

Thông số mẫu của bạn là đã được chỉ định - chúng là các ký tự mã nguồn bao gồm giá trị theo nghĩa đen của bạn! Vì vậy, đối với 10_x, bạn thực sự đang gọi:

template<> double operator "" _x<'1', '0'>(); 

Đây là ví dụ làm việc. Nó biên dịch không có lỗi và không có xác nhận nào được kích hoạt.

#include <cassert> 

enum class MyEnum 
{ 
    ONE, 
    TWO, 
    THREE 
}; 

template<char...> MyEnum operator "" _e(); 

template<> MyEnum operator "" _e<'1'>() 
{ 
    return MyEnum::ONE; 
} 
template<> MyEnum operator "" _e<'2'>() 
{ 
    return MyEnum::TWO; 
} 
template<> MyEnum operator "" _e<'3'>() 
{ 
    return MyEnum::THREE; 
} 

int main() 
{ 
    assert(1_e == MyEnum::ONE); 
    assert(2_e == MyEnum::TWO); 
    assert(3_e == MyEnum::THREE); 
} 
+0

Đó là một ví dụ hay! Vì vậy, cách duy nhất để * truy cập * 'char' là thông qua các chuyên ngành. – vsoftco

+1

Không, bạn cũng có thể làm ví dụ 'template const char * toán tử "" _cs() {static const char arr [] = {Cs ...,' \ 0 '}; return arr; } ' – aschepler

+0

@aschepler Cảm ơn, điểm tốt! – vsoftco

2

Bạn có thể xây dựng các thông số gói bằng cách nào đó (như đã đề cập bởi những người khác) hoặc truy cập chúng như là một chuỗi thời gian biên dịch nếu bạn thích:

template<int N> 
constexpr double f(const char(&str)[N]) { return .42; } 

template <char... C> 
constexpr double operator "" _x() 
{ 
    return f({C...}); 
} 

Bạn có bất cứ ví dụ về gian thực thế giới sử dụng các nhà khai thác templated như vậy?

Bạn có thể sử dụng kỹ thuật nêu trên để đối phó với thời gian biên dịch chuỗi-to-num chuyển đổi và có cái gì đó như 10_x thay vì f("10") hoặc bất cứ điều gì.

+3

Bạn không thể viết 'warrior_x'. – Barry

+0

@Barry Fair đủ. Đã sửa. Tôi đã bao giờ quên (hãy để tôi nói) _constraints_ trên các mẫu toán tử. Cảm ơn. – skypjack

Các vấn đề liên quan