2011-12-15 34 views
5

Tôi có một chức năng mẫu và muốn đảm bảo tại thời gian biên dịch mà nó không được khởi tạo trên một loại phụ hoặc siêu kiểu của một lớp cụ thể.Làm cách nào để tạo một xác nhận thời gian biên dịch cho một mẫu có các loại cụ thể?

Làm cách nào tôi có thể gây ra lỗi trình biên dịch C++ nếu điều này bị vi phạm?

class base { 
}; 
class derived : public base { 
}; 
class lowest : public derived { 
}; 

template <typename T> 
bool isCorrect(const T& obj) { 
    typedef foo<T> D; 
    foo<T> *def = foo<T>::find(); 
    return (def && def->getAnswer(object)); 
} 

Tôi muốn isCorrect chỉ có sẵn cho lớp derived, nhưng không base hoặc lowest. Lưu ý có thể có nhiều lớp thấp nhất khác và một chuỗi các lớp cơ sở cần loại trừ cũng như các lớp dẫn xuất thay thế được chấp nhận.

Có cách nào trong C++ để giới hạn mẫu chỉ áp dụng cho các lớp dẫn xuất mà tôi chỉ định rõ ràng không?

+0

thể trùng lặp của [Mẫu ràng buộc C++] (http://stackoverflow.com/questions/122316/template-constraints-c) –

+0

Cụ thể, điều này có thể hữu ích: http://www.boost.org/doc/libs/1_48_0/libs/concept_check/concept_check.htm –

+0

Tại sao bạn không viết quá tải? – GManNickG

Trả lời

4

Đây là một kỹ thuật mà tôi biết.

Trước tiên, hãy tạo một lớp mẫu khác policy_enforcer. Khai báo lớp này mà không cần định nghĩa nó, và cũng có thể cung cấp một chuyên môn hóa của nó cho derivedđó cũng được định nghĩa:

template<typename T> struct policy_enforcer; 
template<> struct policy_enforcer<derived> { }; 

Sau đó, trong phạm vi chức năng bạn muốn khóa xuống, bao gồm các biểu hiện sizeof(policy_enforcer<T>). Vì sizeof đối với các loại không đầy đủ là một lỗi biên dịch, điều này sẽ ngăn không cho mã biên dịch.

cập nhật với mã trực tiếp:using base, using derived, using lowest.

+0

Một chút ngớ ngẩn, nhưng nó sẽ hoạt động. Hy vọng rằng ai đó sẽ đăng một cách mà không phải là quá tối nghĩa. – WilliamKF

9

Nhập các đặc điểm, cụ thể là is_base_of.

#include <type_traits> 

template <typename T> 
bool isCorrect(const T& obj) { 
    static bool const is_base = std::is_base_of<base, T>::value; 
    static bool const derives = std::is_base_of<derived, T>::value; 
    // specify allowed types here 
    static bool const is_derived = std::is_same<T, derived>::value; 
    // --- 
    static_assert((!is_base && !derives) || is_derived, "wrong argument type"); 

    typedef foo<T> D; 
    foo<T> *def = foo<T>::find(); 
    return (def && def->getAnswer(object)); 
} 

Lưu ý rằng đây là C++ 11 cụ thể, nhưng bạn có thể nhận được hành vi tương tự với Boost.TypeTraits.

1

Bạn có thể sử dụng chuyên môn mẫu.

Bạn chỉ có thể triển khai isCorrect cho các loại mà bạn muốn có thể làm việc.

Đối với các loại khác, bạn có thể triển khai phương pháp giả, trả lại false ví dụ hoặc không thực hiện isCorrect, trong trường hợp đó, nó sẽ không biên dịch cho các loại khác.

#include <iostream> 

using namespace std; 

class base { 
}; 
class derived : public base { 
}; 
class lowest : public derived { 
}; 

// using this it will fail if you try to pass anything 
// else than `derived` 
// template <typename T> 
//  bool isCorrect(const T& obj); 

template <typename T> 
bool isCorrect(const T& obj) { 
    cout << __PRETTY_FUNCTION__ << endl; 
    return false; 
} 

template <> 
bool isCorrect<derived>(const derived& obj) { 
    cout << __PRETTY_FUNCTION__ << endl; 
    return true; 
// typedef foo<derived> D; 
// foo<derived> *def = foo<derived>::find(); 
// return (def && def->getAnswer(object)); 
} 

Test:

int main() 
{ 
    base b; 
    derived d; 
    lowest l; 

    cout << isCorrect(b) << endl; 
    cout << isCorrect(d) << endl; 
    cout << isCorrect(l) << endl; 
} 

Output:

bool isCorrect(const T&) [with T = base] 
0 
bool isCorrect(const T&) [with T = derived] 
1 
bool isCorrect(const T&) [with T = lowest] 
0 
+0

'__func__' là tương đương C++ 11 của' __FUNCTION__', '__PRETTY_FUNCTION__', v.v. – Xeo

+0

Nó không tương đương .... Thứ nhất, tôi không thấy bất kỳ yêu cầu nào cho C++ 11, bất cứ điều gì sai với' __PRETTY_FUNCTION__ ', nó không phải là một phần của câu hỏi, btw cảm ơn thông tin :)? Với '__func__' hoặc' __FUNCTION__' bạn chỉ nhận được 'isCorrect' hoặc' isCorrect 'vì vậy bạn không thấy các kiểu khác được gọi là phiên bản không chuyên ... – stefanB

+0

Không có gì sai, tôi chỉ muốn đề cập đến điều đó, vì C++ 11 là chuẩn hiện hành. Mọi thứ khác ('__FUNCTION__',' __PRETTY_FUNCTION__', v.v.) không phải là tiêu chuẩn và không di động phần lớn thời gian. :) – Xeo

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