2015-11-20 21 views
5

Giả sử tôi xác định một mẫu T có sử dụng một lớp lồng nhau của các mẫu tham số P, như sau:Sử dụng lớp lồng nhau của các mẫu tham số trong CRTP

template<class P> class T 
{ 
public: 
    T(P& p) : p(p) {} 
    P& p; 
    typename P::Nested& get_nested() { return p.nested; } 
}; 

Nếu tôi khai báo một lớp A trong đó bao gồm một lớp lồng nhau đặt tên Nested, tôi có thể xác định một biến kiểu T<A> với không có vấn đề:

class A 
{ 
public: 
    class Nested 
    { 
    public: 
     int i; 
    }; 
    Nested nested; 
}; 

void test2a() 
{ 
    A a; 
    a.nested.i = 1; 
    T<A> t_a(a); 
    t_a.get_nested().i = 2; 
} 

Bây giờ, tôi muốn khai báo một lớp B đó, trong cùng một cách, bao gồm một CLA lồng nhau ss tên Nested và được thừa kế từ T<B>, như sau:

class B : public T<B> 
{ 
public: 
    class Nested 
    { 
    public: 
     int i; 
    }; 
    Nested nested; 
}; 

Compilation của các mã trên không thành công với lỗi: "Nested chưa là thành viên của B"

Tôi nghĩ rằng tôi hiểu những gì là xảy ra: tại thời điểm mẫu được nhập, lớp B không được xác định hoàn toàn do thừa kế.

Tuy nhiên, tôi tự hỏi nếu có bất kỳ cách nào để làm một điều như vậy ...

Cảm ơn bạn đã trợ giúp.

Trả lời

3

tôi đã có thể có ví dụ của bạn biên dịch với chỉ đơn giản

template<class P> class T 
{ 
public: 
    T(P& p) : p(p) {} 
    P& p; 
    auto& get_nested() { return p.nested; } 
}; 

cách tiếp cận khác, khai thác các trick giống như @ecatmur, nhưng một chút đơn giản hơn:

template<class R = P> 
typename R::Nested& get_nested() { return p.nested; } 

Tương tự như vậy, ở đây trình biên dịch có trì hoãn việc đánh giá P::Nested cho đến khi bạn gọi get_nested().

+0

Cảm ơn bạn rất nhiều vì những thủ thuật này, cả Petr và ecatmur. Tuy nhiên, tôi đang sử dụng trình biên dịch MSVC 2010 mà sẽ không biên dịch bất kỳ của họ. Tôi đang suy nghĩ nghiêm túc về việc nâng cấp lên trình biên dịch tuân thủ C++ 14 ... bây giờ. Dù sao, cảm ơn rất nhiều cho câu trả lời của bạn. – shrike

+0

@SharpDressedMan, vấn đề chính xác và thông báo lỗi chính xác với giải pháp thứ hai của tôi là gì? Dường như thậm chí là C++ 03 đối với tôi ... – Petr

+0

Lỗi là C4519: đối số mẫu mặc định chỉ được phép trên mẫu lớp. – shrike

6

Bạn cần hoãn độ phân giải của loại trả lại get_nested cho đến khi được gọi.

Một cách để làm điều này là để làm cho kiểu trả về phụ thuộc vào một mẫu tham số:

template<typename unused = void> 
    typename std::conditional<false, unused, P>::type::Nested& 
    get_nested() { return p.nested; } 

Một cách khác (vì C++ 14) là sử dụng kiểu trả về khấu trừ:

auto& get_nested() { return p.nested; } 
Các vấn đề liên quan