5

Giả sử chúng ta có lớp mẫu sauTrợ giúp với loại đặc điểm mà

template<typename T> class Wrap { /* ... */ }; 

Chúng tôi không thể thay đổiWrap. Nó quan trọng.

Cho phép có các lớp học bắt nguồn từ Wrap<T>. Ví dụ,

class NewInt : public Wrap<int>  { /* ... */ }; 
class MyClass : public Wrap<myclass> { /* ... */ }; 
class Foo  : public Wrap<Bar>  { /* ... */ }; 

Chúng tôi không thể thay đổi các lớp này quá. Tất cả các lớp trên là bên thứ 3. Chung không thuộc vê tôi.

Tôi cần thời gian biên dịch sau type_traits:

template<class T> 
struct is_derived_from_Wrap { 
    static const bool value = /* */; 
}; 

Tôi cần những gì?

assert(is_derived_from_Wrap<Int>::value == true); // Indeed I need static assert 
assert(is_derived_from_Wrap<MyClass>::value == true); 
assert(is_derived_from_Wrap<char>::value == false); 
struct X {}; 
assert(is_derived_from_Wrap<X>::value == false); 
+0

Nhưng bạn có thể thay đổi 'Int' và' MyClass' không? : p – kennytm

+0

No. Cảm ơn bạn đã gợi ý. –

+2

Chẳng phải việc đặt tên tốt hơn cho các đặc điểm kiểu của bạn là: 'has_Wrap_for_base'? Trên thực tế, MyClass không phải là một cơ sở của Wrap. –

Trả lời

9

Bạn có thể làm điều này bằng SFINAE nhưng loại hình này của huyền diệu nếu bạn không biết whats going on ...

template<typename T> class Wrap { }; 

struct myclass {}; 
struct X {}; 

class Int  : public Wrap<int>  { /* ... */ }; 
class MyClass : public Wrap<myclass> { /* ... */ }; 

template< typename X > 
struct is_derived_from_Wrap 
{ 
    struct true_type { char _[1]; }; 
    struct false_type { char _[2]; }; 

    template< typename U > 
    static true_type test_sfinae(Wrap<U> * w); 
    static false_type test_sfinae(...); 

    enum { value = sizeof(test_sfinae((X*)(0)))==sizeof(true_type) }; 
}; 


#include <iostream> 
#define test(X,Y) std::cout<<(#X " == " #Y)<<" : "<<((X)?"true":"false") <<std::endl; 

int main() 
{ 
    test(is_derived_from_Wrap <Int>::value, true); 
    test(is_derived_from_Wrap <MyClass>::value, true); 
    test(is_derived_from_Wrap <char>::value, false); 
    test(is_derived_from_Wrap <X>::value, false); 
} 

này mang lại cho sản lượng dự kiến ​​

is_derived_from_Wrap <Int>::value == true : true 
is_derived_from_Wrap <MyClass>::value == true : true 
is_derived_from_Wrap <char>::value == false : false 
is_derived_from_Wrap <X>::value == false : false 

Có một vài gotchas với mã của tôi. Nó cũng sẽ trả về true nếu kiểu là một Wrap.

assert( is_derived_from_Wrap< Wrap<char> >::value == 1); 

Điều này có thể được khắc phục bằng ma thuật SFINAE hơn một chút nếu cần.

Nó sẽ trả về false nếu nguồn gốc không phải là một nguồn gốc nào (nghĩa là private hay protected)

struct Evil : private Wrap<T> { }; 
assert(is_derived_from_Wrap<Evil>::value == 0); 

Tôi nghi ngờ điều này không thể được cố định. (Nhưng tôi có thể sai). Nhưng tôi nghi ngờ thừa kế công khai là đủ.

+0

Tôi cho rằng sau đó chuyên môn hóa một phần đơn giản như trong mã của tôi sẽ không hoạt động? – sbi

+0

Đúng như chuyên môn sẽ chỉ phù hợp nếu loại khớp chính xác. Your_Wrap < Wrap> :: value = true, nhưng is_Wrap :: value = false. –

+0

Tuyệt vời. Tôi đã từng nghĩ rằng 'test_sfinae (Wrap * w);' không thể suy ra 'U' đối với trường hợp' X * '. –

0

Sau đây sẽ xác định xem một cái gì đó một bọc:

template<class T> 
struct is_Wrap { static const bool value = false; }; 

template<typename T> 
struct is_Wrap< Wrap<T> > { static const bool value = true; }; 

Kể từ nguồn gốc là một Is-Một mối quan hệ, mọi thứ đều bắt nguồn từ Wrap<T> cũng là một Wrap<T> và cần được tìm thấy bằng cách này.

+0

Tên tôi 'cơ sở của Wrap' là sai. Tiếng anh xấu của tôi. 'Có nguồn gốc từ bọc', tất nhiên. –

+0

Nó không phải là giải pháp rất tốt. Sau đó, tôi cần phải làm cho DEFINE cho mỗi lớp. Tôi không biết tất cả chúng. Tôi muốn nhận biết liệu X có xuất phát từ Wrap trong đó Y có thể là bất kỳ loại nào hay không. –

+0

@Alexey: Tôi sẽ cố gắng điều chỉnh mã của mình cho phù hợp. Nhưng bạn chắc chắn cần phải chính xác hơn trong việc đặt câu hỏi của bạn. (Và đó không chỉ là một vấn đề rào cản ngôn ngữ.) – sbi

0

Bạn cần thực hiện một số mẫu siêu lập trình liên quan đến mẫu để xác định xem một lớp X có xuất phát từ một Y khác hay không, trong trường hợp chung. Về cơ bản X có nguồn gốc từ Y nếu:

  1. Y có thể được ngầm chuyển đổi sang X
  2. X và Y là không cùng loại

Andrei Alexandrescu giải thích làm thế nào để làm điều này (cùng với nhiều mẫu thủ thuật khác) trong cuốn sách "Thiết kế C++ hiện đại".

Bạn có thể tìm mã giải quyết vấn đề của mình trong thư viện Loki hoặc triển khai uSTL, cả hai được viết bởi Alexandrescu.

+1

Sau khi đọc lại câu hỏi, tôi nhận thấy rằng đề xuất của tôi không giải quyết được vấn đề. Chúng tôi không muốn biết liệu X có xuất phát từ Y hay không, nhưng liệu X có xuất phát từ Y hay không, trong đó T có thể là bất kỳ loại nào. –

+0

Có. Câu trả lời của bạn không phải là giải pháp. Nhưng bạn đã nhận ra vấn đề. –

+0

Bạn cũng có thể trích dẫn tăng :: is_base_of (không giải quyết vấn đề của OP vì tham số Base không thể là mẫu lớp). –

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