2010-07-04 35 views
55

Làm cách nào để buộc tham số mẫu T làm lớp con của một lớp cụ thể Baseclass? Something như thế này:Hạn chế tham số mẫu C++ thành lớp con

template <class T : Baseclass> void function(){ 
    T *object = new T(); 

} 
+3

Bạn đang cố gắng thực hiện điều gì bằng cách thực hiện việc này? – sth

+2

Tôi chỉ muốn đảm bảo rằng T thực sự là một thể hiện của một lớp con hoặc chính lớp đó. Mã bên trong hàm mà tôi đã cung cấp là khá nhiều không liên quan. – phant0m

+6

ngược lại, nó rất phù hợp. Nó xác định xem đó là một ý tưởng hay không để đưa công việc vào thử nghiệm đó. Trong nhiều trường hợp (tất cả?), Hoàn toàn không cần phải thực thi các ràng buộc như vậy, mà là để cho trình biên dịch làm điều đó khi khởi tạo. Ví dụ, đối với câu trả lời được chấp nhận, nó sẽ là tốt để đặt một kiểm tra xem liệu 'T' có nguồn gốc từ' Baseclass' hay không. Hiện tại, kiểm tra đó là ẩn và không hiển thị với độ phân giải quá tải. Nhưng nếu hư không như một ràng buộc tiềm ẩn được thực hiện, dường như không có lý do gì để hạn chế nhân tạo. –

Trả lời

44

Trong trường hợp này bạn có thể làm:

template <class T> void function(){ 
    Baseclass *object = new T(); 

} 

này sẽ không biên dịch nếu T không phải là một lớp con của BaseClass (hoặc T BaseClass).

+0

ah vâng, đó là một ý tưởng hay. cảm ơn! Tôi lấy nó sau đó không có cách nào để xác định nó trong định nghĩa mẫu? – phant0m

+2

@ phant0m: Đúng. Bạn không thể hạn chế một cách rõ ràng các tham số mẫu (ngoại trừ việc sử dụng các khái niệm, được xem xét cho C++ 0x nhưng sau đó bị loại bỏ). Tất cả các ràng buộc xảy ra ngầm bởi các thao tác bạn thực hiện trên nó (hoặc nói cách khác ràng buộc duy nhất là "Kiểu phải hỗ trợ tất cả các hoạt động được thực hiện trên nó"). – sepp2k

+1

ah ic. Cảm ơn rất nhiều vì đã làm rõ! – phant0m

0

Bằng cách gọi hàm bên trong mẫu của bạn tồn tại trong lớp cơ sở.

Nếu bạn thử và khởi tạo mẫu của mình bằng loại không có quyền truy cập chức năng này, bạn sẽ nhận được lỗi biên dịch.

+2

Điều này không đảm bảo rằng 'T' * là *' BaseClass' vì các thành viên được khai báo trong 'BaseClass' có thể được lặp lại trong khai báo' T'. –

5

Bạn có thể sử dụng Boost Concept Check 's BOOST_CONCEPT_REQUIRES:

#include <boost/concept_check.hpp> 
#include <boost/concept/requires.hpp> 

template <class T> 
BOOST_CONCEPT_REQUIRES(
    ((boost::Convertible<T, BaseClass>)), 
(void)) function() 
{ 
    //... 
} 
+0

cảm ơn đề xuất. Tôi sẽ kiểm tra nó. – phant0m

8

Bạn không cần phải khái niệm, nhưng bạn có thể sử dụng SFINAE:

template <typename T> 
boost::enable_if< boost::is_base_of<Base,T>::value >::type function() { 
    // This function will only be considered by the compiler if 
    // T actualy derived from Base 
} 

Lưu ý rằng điều này sẽ nhanh chóng các chức năng chỉ khi điều kiện được đáp ứng, nhưng nó sẽ không cung cấp một lỗi hợp lý nếu điều kiện không được đáp ứng.

+0

Nếu bạn bọc tất cả các chức năng như thế này thì sao? btw nó trở lại cái gì? –

+0

'enable_if' lấy tham số kiểu thứ hai mặc định là' void'. Biểu thức 'enable_if < true, int > :: type' thể hiện kiểu' int'. Tôi không thể thực sự hiểu câu hỏi đầu tiên của bạn là gì, bạn có thể sử dụng SFINAE cho bất cứ điều gì bạn muốn, nhưng tôi không hoàn toàn hiểu những gì bạn định làm với điều này trên tất cả các chức năng. –

39

Để thực thi ít mã không dùng được khi chạy, bạn có thể xem: http://www.stroustrup.com/bs_faq2.html#constraints cung cấp một số lớp thực hiện kiểm tra thời gian biên dịch hiệu quả và tạo ra thông báo lỗi đẹp hơn.

Đặc biệt:

template<class T, class B> struct Derived_from { 
     static void constraints(T* p) { B* pb = p; } 
     Derived_from() { void(*p)(T*) = constraints; } 
}; 

template<class T> void function() { 
    Derived_from<T,Baseclass>(); 
} 
+1

cảm ơn liên kết! – phant0m

+1

Đối với tôi, đây là câu trả lời hay nhất và thú vị nhất. Hãy chắc chắn kiểm tra Stroustrup's FAQ để đọc thêm về tất cả các loại ràng buộc mà bạn có thể thực thi tương tự như vậy. –

+1

Thật vậy, đây là một câu trả lời! Cảm ơn. Trang web được đề cập được di chuyển tại đây: http://www.stroustrup.com/bs_faq2.html#constraints –

54

Với C++ 11 trình biên dịch phù hợp, bạn có thể làm một cái gì đó như thế này:

template<class Derived> class MyClass { 

    MyClass() { 
     // Compile-time sanity check 
     static_assert(std::is_base_of<BaseClass, Derived>::value, "Derived not derived from BaseClass"); 

     // Do other construction related stuff... 
     ... 
    } 
} 

Tôi đã thử nghiệm điều này bằng cách sử dụng trình biên dịch gcc 4.8.1 bên trong môi trường CYGWIN - vì vậy nó cũng hoạt động trong môi trường * nix.

+0

Đối với tôi, nó cũng hoạt động như sau: 'template class BaseBiz { static_assert (std :: is_base_of :: value," TEntity not origin from BaseEntity "); ... ... –

+0

chỉ hoạt động nếu toàn bộ mẫu nằm trong tiêu đề. – peterh

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