2013-08-22 31 views
6

Tôi đang cố sử dụng dạng CRTP đơn giản (Mẫu tò mò định kỳ) vì tôi có nhiều lớp, mỗi lớp có một số lớp liên quan và tôi muốn có phương thức ràng buộc chúng cùng nhau (ví dụ như tôi đã có các lớp như Widget, Doobry và Whatsit, với các lớp có liên quan WidgetHandle, DoobryHandle và WhatsitHandle).Lỗi biên dịch cho trường hợp CRTP đơn giản với các kiểu phụ thuộc

Mỗi lớp mà tôi đang sử dụng để kế thừa từ Base thêm một typaief value_type để lớp cơ sở có thể tham chiếu đến nó là typename TWrapper::value_type.

struct WidgetHandle {}; 

template <typename TWrapper> 
class Base 
{ 
public: 
    Base(typename TWrapper::value_type value_) 
     : value(value_) {} 

    typename TWrapper::value_type value; 
}; 

class Widget : public Base<Widget> 
{ 
public: 
    typedef WidgetHandle value_type; 

    Widget(WidgetHandle value_) : Base<Widget>(value_) {} 
}; 

int main(int argc, char* argv[]) 
{ 

    Widget i(WidgetHandle()); 
    return 0; 
} 

Tuy nhiên, tôi nhận được lỗi biên dịch:

scratch1.cpp(10): error C2039: 'value_type' : is not a member of 'Widget' 
scratch1.cpp(16) : see declaration of 'Widget' 
scratch1.cpp : see reference to class template instantiation 'Base<TWrapper>' being compiled 
1>   with 
1>   [ 
1>    TWrapper=Widget 
1>   ] 
scratch1.cpp(10): error C2039: 'value_type' : is not a member of 'Widget' 

Đây là với VS2010, mặc dù tôi nhận được lỗi tương tự với kêu vang. Tôi đang thiếu gì ở đây?

+0

'Widget' là loại không đầy đủ khi bạn chuyển nó làm tham số cho' Cơ sở'. – jrok

+0

Tôi không thấy 'giá trị_type' được xác định ở bất kỳ đâu, trên thực tế. – lapk

+0

@PetrBudnik Đó là, lúc bắt đầu của 'Widget' cơ thể. – jrok

Trả lời

1

Thay đổi định nghĩa cơ sở để lấy ha loại ndle như một tham số thứ hai để tránh sự phụ thuộc vòng tròn.

struct WidgetHandle {}; 

template <typename TWrapper, typename HandleType> 
class Base 
{ 
public: 
    typedef HandleType value_type; 

    Base(HandleType value_) 
     : value(value_) {} 

    HandleType value; 
}; 

class Widget : public Base<Widget, WidgetHandle> 
{ 
public: 
    Widget(WidgetHandle value_) : Base(value_) {} 
}; 

int main(int argc, char* argv[]) 
{ 

    Widget i(WidgetHandle()); 
    return 0; 
} 

Bạn cũng có thể sử dụng lớp đặc điểm để nhận loại WidgeHandle cho Widget.

struct WidgetHandle {}; 
class Widget; 

template<class T> 
struct Handle 
{ 
}; 

template<> 
struct Handle<Widget> 
{ 
    typedef WidgetHandle type; 
}; 

template <typename TWrapper, typename HandleType = Handle<TWrapper>::type> 
class Base 
{ 
public: 
    typedef HandleType value_type; 

    Base(HandleType value_) 
     : value(value_) {} 

    HandleType value; 
}; 

class Widget : public Base<Widget> 
{ 
public: 
    Widget(WidgetHandle value_) : Base(value_) {} 
}; 

int main(int argc, char* argv[]) 
{ 

    Widget i(WidgetHandle()); 
    return 0; 
} 
+0

Tôi biết tôi có thể thêm các kiểu bổ sung vào định nghĩa mẫu, nhưng thật không may khi yêu cầu điều này nếu TWrapper có phương tiện chỉ định loại mà nó liên kết với –

+0

Sử dụng tham số mẫu mặc định để lấy loại xử lý từ lớp đặc điểm - sau đó ít nhất mã máy khách sẽ trông giống nhau. – paxos1977

+0

Điều đó có tác dụng. Trong trường hợp của tôi, tôi có một số loại có liên quan cho mỗi lớp, do đó buộc chúng cùng với lớp Đặc điểm xử lý có nghĩa là tất cả chúng có thể được khai báo trong một lớp. –

1

Bạn không thể có phụ thuộc vòng tròn: Cơ sở cần giá trị Widget_type không xác định tại Bản dựng cơ sở.

Giải pháp có thể sẽ là: Vượt qua value_type như một tham số cơ sở mẫu, sử dụng một đặc điểm phụ mẫu, ...

Ví dụ:

template <typename W> 
struct WidgetTraits {}; 

template <typename W> 
class Base 
{ 
    public: 
    typedef typename WidgetTraits<W>::value_type value_type; 
}; 

class Widget; 

template<> 
struct WidgetTraits<Widget> 
{ 
    typedef WidgetHandle value_type; 
}; 

class Widget : public Base<Widget> 
{ 
}; 

khác (hơi khác nhau) Ví dụ :

template <typename C, typename A> 
class B : public A 
{ 
    public: 
    typedef typename A::value_type value_type; 
}; 


class A 
{ 
    public: 
    typedef WidgetHandle value_type; 
}; 


class C : public B<C, A> 
{ 
}; 
+0

Đó là sự thật nói chung, nhưng CRTP sử dụng kỹ thuật này rộng rãi phải không? http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern –

+0

ok, mẫu đặc điểm có vẻ như có thể tốt hơn - trông như thế nào? –

+0

Giải pháp đặc điểm phức tạp hơn ... Tôi sẽ tìm tham số mẫu bổ sung. – Walter

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