I'm trying to use a simple form of CRTP (Curiously Recurring Template Pattern) as I've got several classes, each with several related classes, and I want a means of binding them together (eg I've got classes like Widget, Doobry and Whatsit, with related classes WidgetHandle, DoobryHandle and WhatsitHandle).
Each class that I'm using to inherit from Base
adds a value_type
typedef so that the base class can refer to it as 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;
}
However, I'm getting compilation errors:
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'
This is with VS2010, though I'm getting similar errors with clang. What am I missing here?
Change the definition of Base to take the handle type as a second parameter to avoid the circular dependency.
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;
}
You could also use a traits class to get the WidgeHandle type for 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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With