2011-08-15 22 views
31

Tôi có một mẫu tem class (gọi là Foo) có một số chuyên môn. Tôi muốn quá trình biên dịch thất bại nếu ai đó cố gắng sử dụng phiên bản không chuyên biệt của Foo.Làm cách nào để ngăn chặn việc tạo mẫu không chuyên biệt?

Dưới đây là những gì tôi thực sự có:

template <typename Type> 
class Foo 
{ 
    Foo() { cannot_instantiate_an_unspecialized_Foo(); } 

    // This method is NEVER defined to prevent linking. 
    // Its name was chosen to provide a clear explanation why the compilation failed. 
    void cannot_instantiate_an_unspecialized_Foo(); 
}; 

template <> 
class Foo<int> 
{ }; 

template <> 
class Foo<double> 
{ }; 

Vì vậy mà:

int main() 
{ 
    Foo<int> foo; 
} 

trình khi:

int main() 
{ 
    Foo<char> foo; 
} 

Liệu không.

Rõ ràng, chuỗi trình biên dịch chỉ phàn nàn khi quá trình liên kết diễn ra. Nhưng có cách nào để làm cho nó phàn nàn trước?

Tôi có thể sử dụng boost.

Trả lời

35

Chỉ cần không xác định lớp:

template <typename Type> 
class Foo; 

template <> 
class Foo<int> { }; 

int main(int argc, char *argv[]) 
{ 
    Foo<int> f; // Fine, Foo<int> exists 
    Foo<char> fc; // Error, incomplete type 
    return 0; 
} 

Tại sao công việc này? Đơn giản vì có không phải là bất kỳ mẫu chung nào. Đã khai báo, có, nhưng không được xác định.

+1

Cảm ơn bạn rất nhiều. Tôi đoán tôi đang tìm thứ gì đó quá phức tạp. – ereOn

+0

@Schnommus Nhưng nếu bạn định nghĩa lớp và nó có một static_assert, không nên nó không bao giờ được khởi tạo bởi vì chuyên môn phù hợp hơn? –

+0

Đó là quyết định tồi, vì lỗi sẽ được phát hành trên liên kết giai đoạn, không phải trên biên dịch. Và bạn sẽ không bao giờ biết chính xác bạn đã sử dụng lớp học không chuyên môn ở đâu. – vladon

17

Bạn có thể chỉ đơn giản là không xác định trường hợp cơ sở:

template <typename> class Foo;    // no definition! 

template <> class Foo<int> { /* ... */ }; // Foo<int> is OK 
+6

Tôi không thể tin rằng tôi đã bỏ lỡ điều đó ... Cảm ơn bạn. Câu trả lời Schnommus được chấp nhận bởi vì anh ta có danh tiếng thấp hơn. Upvoted này một cho sự công bằng. – ereOn

13

Một trick cho C++ 0x (cũng có sẵn với một thi đua 03 static_assert C++, nhưng được thông báo lỗi không nhất thiết phải tốt hơn thay vì để mẫu chính chưa được xác định):

template<typename T> 
struct dependent_false: std::false_type {}; 

template<typename Type> 
struct Foo { 
    static_assert(dependent_false<Type>::value 
       , "Only specializations of Foo may be used"); 
}; 

Xác nhận sẽ chỉ kích hoạt khi Foo được khởi tạo với mẫu chính. Sử dụng static_assert(false, ...) sẽ kích hoạt xác nhận mọi lúc.

+0

+1. Cảm ơn bạn đã lừa. – ereOn

+2

Một mẹo tương tự cần ít hơn để gõ là sử dụng static_assert (sizeof (Type) == 0, "..."); Thay vào đó, bạn có thể sử dụng BOOST_STATIC_ASSERT. Cá nhân tôi thích những điều đó, như ở trên "không xác định mẫu cơ sở" có thể dẫn đến lỗi trình liên kết khi bạn chỉ làm việc với các tham chiếu/con trỏ. Cũng thường bạn nên dừng lại một lúc và suy nghĩ lại nếu bạn thực sự cần điều này, vì các khuôn mẫu có nghĩa là chung chung, mà bạn đang hạn chế ở đây – PlasmaHH

+0

Làm thế nào để nó hoạt động? Bạn sẽ không cần phải định nghĩa 'depend_false : std :: true_type {}' cho mỗi 'Chuyên môn', hoặc khác' depend_false :: giá trị' sẽ luôn là sai? – mako

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