2012-01-25 20 views
5

Tôi đang sử dụng 'thủ thuật' sau khi biên dịch (dựa trên ADL) để tạo một hàm chỉ hợp lệ/được định nghĩa/có thể gọi bởi các lớp trong cùng một không gian tên.Chuyên dùng mẫu phương thức cho các lớp trong không gian tên

namespace Family1 
    { 
     struct ModelA{}; 
     struct ModelB{}; 

     template<typename T> 
     bool is_in_Family1(T const& t) 
     { 
      return true; 
     } 
    }; 

    namespace Family2 
    { 
     struct ModelC{}; 

     template<typename T> 
     bool is_in_Family2(T const& t) 
     { 
      return true; 
     } 
    }; 


    Family1::ModelA mA; 
    Family2::ModelC mC; 

    is_in_Family1(mA);   // VALID 
    is_in_Family1(mC);   // ERROR 

Bây giờ, tôi muốn sử dụng nguyên tắc này (hoặc một cái gì đó tương tự) để sản xuất một chuyên môn của Foo::Bar (dưới đây) cho các lớp học thuộc cho mỗi không gian tên ví dụ Family1.

// I would like to specialize the method template Bar for classes in Family1 
    // namespace; and another specialization for classes in Family2 namespace 
    struct Foo 
    { 
     template<typename T> 
     void Bar(T& _T){} 
    }; 

Để dễ bảo trì và số lượng lớn các lớp trong mỗi không gian tên, nếu có thể, tôi muốn thực hiện kiểm tra này mà không đặt tên tất cả các lớp trong không gian tên.

+0

Tại sao 'Foo' một lớp mẫu của người xây dựng cũng là một mẫu với một kiểu khác? 'Foo myvar ('4');'? Ý của bạn chỉ có một mẫu 'template '? Bởi vì cái bên ngoài không được sử dụng. Tôi nghĩ rằng điều này có thể được thực hiện nếu 'Foo' chỉ là một chức năng, nhưng tôi không nghĩ nó có thể là một cấu trúc. Hoặc ít nhất, không độc đáo. –

Trả lời

0

Cách nhanh nhất tôi tìm thấy để làm điều này là sử dụng Loại Boost đặc điểm is_base_of <>

Tôi cố gắng để sử dụng thừa kế với mẫu chuyên môn nhưng điều đó không làm việc vì thừa kế bị bỏ qua khi mẫu chuyên môn được sử dụng, do đó bạn 'd phải chuyên cho từng mô hình. Câu trả lời cho Partial specialization for a parent of multiple classes giải thích sự cố.

Sử dụng đặc điểm loại công trình cung cấp bạn thực hiện Family1 :: ModelA và Gia đình :: ModelB lớp con của Family1: Family1Type và Family2 :: ModelC một lớp con của Family2 :: Family2Type:

#include <iostream> 
#include <boost/type_traits/is_base_of.hpp> 

namespace Family1{ 

    struct Family1Type{}; 

    struct ModelA :public Family1Type{}; 
    struct ModelB :public Family1Type{}; 

    template<typename T> 
    bool is_in_Family1(const T& t){ 
     return boost::is_base_of<Family1::Family1Type,T>::value; 
    } 
}; 

namespace Family2{ 
    struct Family2Type{}; 

    struct ModelC :public Family2Type{}; 

    template<typename T> 
    bool is_in_Family2(const T& t){ 
     return boost::is_base_of<Family2::Family2Type,T>::value; 
    } 

}; 

using namespace std; 
int main(int argc, char *argv[]) { 

    Family1::ModelA mA; 
    Family2::ModelC mC; 

    std::cout << "mA is in Family1? " << is_in_Family1(mA) << std::endl; 
    std::cout << "mC is in Family2? " << is_in_Family2(mC) << std::endl; 

    //std::cout << "mC is in Family1? " << is_in_Family1(mC) << std::endl; //ERROR! 
    //std::cout << "mA is in Family2? " << is_in_Family2(mA) << std::endl; //ERROR! 

    return 0; 
} 

Điều này dẫn đến sau đầu ra:

mA is in Family1? 1 
mC is in Family2? 1 

tôi không nghĩ rằng có một cách để khai báo Foo và chuyên Foo::Bar<> trong namespace khác theo Specialization of 'template<class _Tp> struct std::less' in different namespace

+0

Cảm ơn @Joel. Làm thế nào về chuyên môn của 'Foo' cho mỗi không gian tên? – Olumide

+0

Làm xước điều đó. Những gì tôi thực sự muốn làm là để chuyên một phương pháp 'Foo' cho mỗi không gian tên. Tôi đã chỉnh sửa bài đăng của mình cho phù hợp. – Olumide

+0

@Olumide Tôi dường như không thể tìm ra cách thực hiện tại thời điểm này mà không khai báo cấu trúc Foo trong mỗi không gian tên. Tôi dường như không thể định nghĩa Foo bên ngoài một không gian tên nơi tôi thực hiện một chuyên môn của nó. – Joel

1

"mẹo" của bạn có một vấn đề lớn. Hãy thử gọi is_in_Family1(make_pair(Family1::ModelA(), Family2::ModelC()) và bạn sẽ thấy trả lại true, vì ADL sẽ xem xét cả hai không gian tên của ModelAModelC (vì pair<ModelA, ModelC>).

Bỏ qua vấn đề đó, với việc sử dụng các chức năng của bạn, nó sẽ được chuyển thẳng về phía trước.

template<typename T> struct int_ { typedef int type; }; 

struct Foo 
{ 
    template<typename T, 
      typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0 
    > 
    void Bar(T& t){} 

    template<typename T, 
      typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0 
    > 
    void Bar(T& t){} 
}; 

Cuộc gọi đó Bar tùy thuộc vào việc đó là trong family2 hoặc family1.

struct Foo 
{ 
    template<typename T, 
      typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0 
    > 
    void Bar(T& t, long){} 

    template<typename T, 
      typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0 
    > 
    void Bar(T& t, long){} 

    template<typename T> 
    void Bar(T& t, int) {} 

    template<typename T> 
    void Bar(T& t) { return Bar(t, 0); } 
}; 

Đó cũng là một dự phòng chung. Và mã của bạn có hành vi không xác định vì bạn đã sử dụng tên riêng. Không sử dụng _T.

+0

Cảm ơn @litb! (Tôi hiện đang nghiên cứu câu trả lời của bạn.) Có cách nào khác để có 'is_in_Family' trả về boolean không? Sau đó, một lần nữa, tại sao một cặp một đối số hợp lệ cho 'is_in_Family'? – Olumide

+0

@olu dunno về alrernatives. nó là một đối số hợp lệ bởi vì bạn đã tạo nó thành một mẫu để nó chấp nhận bất cứ điều gì. –

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