我正在尝试使用一种简单形式的CRTP(奇怪的重复模板模式),因为我有几个类,每个类都有几个相关的类,我想要一种将它们绑定在一起的方法(例如,我有类比如Widget,Doobry和Whatsit,以及WidgetHandle,DoobryHandle和WhatsitHandle等相关课程。
我用来从Base
继承的每个类都添加了value_type
typedef,以便基类可以将其称为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;
}
但是,我收到了编译错误:
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'
这是VS2010,虽然我在使用clang时遇到了类似的错误。我在这里缺少什么?
答案 0 :(得分:1)
你不能拥有循环依赖:Base需要Widget value_type,这在Base实例化时是未知的。
可能的解决方案是:将value_type作为Base模板参数传递,使用额外的Traits模板,...
示例强>:
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>
{
};
另一个(稍有不同)示例:
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>
{
};
答案 1 :(得分:1)
更改Base的定义,将句柄类型作为第二个参数,以避免循环依赖。
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;
}
您还可以使用traits类来获取Widget的WidgeHandle类型。
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;
}