How to Avoid Errors While Using Crtp

How to avoid errors while using CRTP?

In C++0x you have a simple solution. I don't know whether it is implemented in MSVC10 however.

template <typename T>
struct base
{
private:
~base() {}
friend T;
};

// Doesn't compile (base class destructor is private)
struct foo : base<bar> { ... };

How to secure CRTP against providing wrong superclass?

Make Base's destructor private, and then make Derived a friend of Base<Derived>:

template <class Derived>
class Base {
private: ~Base() = default;
friend Derived;
};

class Derived : public Base<Derived> {
};

This does not actually make doing

class AnotherDerived : public Base<Derived> {
};

illegal, but any attempt to actually construct an AnotherDerived will fail.

Various errors with CRTP (C++)

You need to implement your specialized functions as this:

template<>
const string& Entity<Client>::name() const {
return _name;
}

template<>
Client& Entity<Client>::name(const string& name) {
_name = name;
return *This();
}

and also add public inheritance:

class Client : public Entity<Client>

so you can access name().

If you want generic implementations:

template<class x>
const string& Entity<x>::name() const {
return _name;
}

template<class x>
x& Entity<x>::name(const string& name) {
_name = name;
return *This();
}

Prevent user from deriving from incorrect CRTP base

1) make all constructors of Base private (if there are no constructors, add one)

2) declare Derived template parameter as friend of Base

template <class Derived>
class Base
{
private:

Base(){}; // prevent undesirable inheritance making ctor private
friend Derived; // allow inheritance for Derived

public :

void call ()
{
static_cast<Derived *>(this)->call_impl();
}
};

After this it would be impossible to create any instances of the wrong inherited D2.

CRTP compiling error

Try making it a constexpr function instead. The way you have it setup now attempts to access an incomplete type.

Since a templated member function will only be initialized upon first being used, type A will be fully defined by that point.

#include <iostream>

template <typename Derived>
struct CRTP {
static constexpr int num() { return Derived::value + 1; }
};

struct A : CRTP<A> {
static constexpr int value = 5;
};

int main()
{
std::cout << A::num();
return 0;
}

See it live here

Compile errors for simple CRTP case with dependent types

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;
}


Related Topics



Leave a reply



Submit