2013-07-16 31 views
7

Tôi đang cố gắng hiểu tính hữu dụng của static_assert và tôi muốn biết liệu nó có thể giúp tôi thực thi một thiết kế hay không, và nếu có, làm thế nào.Thực thi loại mẫu thông qua static_assert

Tôi có một lớp mẫu chung ẩn tự thực hiện riêng của mình bên trong một lớp mẫu khác, một phần chuyên biệt dựa trên kích thước của loại mẫu. Dưới đây là một phác thảo ngắn gọn về thiết kế này:

template <class T, size_t S = sizeof(T)> 
struct Helper; 

template <class T> 
struct Helper<T, sizeof(long)> 
{ 
    static T bar(); 
}; 

// ... other specializations ... 

template <class T> 
class Foo 
{ 
public: 

    T bar() 
    { 
     return Helper<T>::bar(); 
    } 
}; 

Foo chỉ được hỗ trợ nếu kích thước của T được hỗ trợ bởi một chuyên môn của Helper. Ví dụ: Foo<long>Foo<unsigned long> đều được hỗ trợ. Tuy nhiên, giả sử người dùng cố gắng tạo một Foo<bool>. Thông thường, điều này sẽ tạo ra lỗi vì chuyên môn của Helper cho bool không được xác định, đó là hành vi dự định.

Có cách nào để sử dụng static_assert trong thiết kế này để cung cấp thêm lỗi hữu ích cho người dùng của giao diện này không?

Ngoài ra, tôi cũng muốn hạn chế người dùng sử dụng một loại cụ thể, mặc dù kích thước có thể chính xác. Ví dụ: Foo<float> không được phép. Ngay bây giờ, cách duy nhất tôi biết thực thi điều này là thông qua một bình luận in đậm trong tài liệu. :)

+0

Suy nghĩ chung hơn, chỉ là các loại số nguyên được hỗ trợ? Không có 'char',' bool', 'float', et al? – Rapptz

+0

Tìm kiếm SO cho các ràng buộc kiểu mẫu hoặc "khái niệm". Một cơ sở để làm điều này đã được gỡ bỏ từ C++ 11 ở phút cuối cùng. Tuy nhiên, có ít cách tự động hơn để đạt được kết quả tương tự. – luke

+0

@Rapptz, 'char',' int' và 'long', cùng với các phiên bản' unsigned' của chúng sẽ được hỗ trợ. Mã sẽ giống hệt nhau cho 'int',' long' và 'unsigned long' nếu' sizeof (int) == sizeof (dài) == sizeof (unsigned long) '. – Zeenobit

Trả lời

1

tôi đã tìm ra một giải pháp tốt hơn cho vấn đề này bằng cách kết hợp các câu trả lời và bình luận ở đây.

tôi có thể xác định một kiểm tra kiểu tĩnh như vậy:

template <class A, class B> 
struct CheckTypes 
{ 
    static const bool value = false; 
}; 

template <class A> 
struct CheckTypes<A, A> 
{ 
    static const bool value = true; 
}; 

Không chắc chắn nếu một cấu trúc như vậy đã tồn tại trong thư viện chuẩn.Dù sao, sau đó trong Foo, tôi có thể kiểm tra các loại và kích cỡ sử dụng:

static_assert((sizeof(T) == sizeof(long) || sizeof(T) == sizeof(int)) && !CheckTypes<T, float>::value, "Error!"); 
+1

, std :: is_same –

+1

sử dụng sizeof không an toàn. nó chỉ là kích thước. long và int có thể có cùng kích thước, và một cấu trúc ngẫu nhiên chỉ chứa một int cũng sẽ có cùng kích thước. –

13

Nếu nó chỉ có thể làm việc cho một chuyên môn hóa của lớp mẫu, sau đó có lớp mẫu mặc định nâng cao một khẳng định tĩnh:

template <class T, size_t S = sizeof(T)> 
struct Helper 
{ 
    static_assert(sizeof(T) == -1,"You have to have a sepecialization for Helper!"); 
} 

Các mẫu mặc định lớp sẽ chỉ được lựa chọn nếu không có một chuyên môn tốt hơn, cho rằng khẳng định sẽ được tăng lên.

Bạn có thể sử dụng cùng một kỹ thuật để không cho phép loại, nhưng bạn sẽ cần một thông số mẫu khác sẽ được sử dụng cho kiểm tra xác nhận tĩnh.

template <class T, class G = T, size_t S = sizeof(T)> 
struct Helper 
{ 
    static_assert(sizeof(G) == -1,"You have to have a sepecialization for Helper!"); 
} 

template <class G> 
struct Helper<float,G> 
{ 
    static_assert(sizeof(G) == -1,"You can't use float !"); 
} 

template <> 
struct Helper<int> 
{ 
//This is a good specialization 
}; 

Sau đó, bạn có thể thử nó với các biến:

Helper<bool> a; //"You have to have a sepecialization for Helper!" 
Helper<float> b; //"You can't use float !" 
Helper<int> c; //compiles OK 
+1

Tôi tin rằng bạn muốn 'static_assert (false, ...)', vì vậy nó luôn luôn đi. 'static_assert' in lỗi nếu đối số đầu tiên là sai. –

+0

+1 cho câu trả lời thực dụng – sehe

+9

Điều này sẽ không hoạt động như - bạn cần phải thực hiện xác nhận phụ thuộc (chẳng hạn như 'static_assert (sizeof (T) == 0, ...);'), nếu không nó sẽ được xử lý tại điểm tuyên bố, không khởi tạo. – Angew

3

http://en.cppreference.com/w/cpp/header/type_traits

std::is_base_ofstd::is_convertible có thể giúp đỡ với vấn đề đầu tiên của bạn và như cho phần thứ hai,

static_assert(!std::is_same<float,T>(),"type can't be float");

hy vọng điều này sẽ giúp người khác gặp khó khăn khi đặt câu hỏi này, giả sử OP có thể tìm thấy câu trả lời trong 4 năm tội lỗi ce it was asked :)

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