Подтвердить что ты не робот

Как избежать ошибок при использовании CRTP?

Используя CRTP, иногда я пишу такой код:

// this was written first
struct Foo : Base<Foo, ...>
{
   ...
};

// this was copy-pasted from Foo some days later
struct Bar : Base<Foo, ...>
{
   ...
};

И очень сложно понять, что пойдет не так, пока я не отсканирую код в отладчике и не увижу, что члены бара не используются в Base.

Как выявить эту ошибку во время компиляции?

(Я использую MSVC2010, поэтому я могу использовать некоторые функции С++ 0x и расширения языка MSVC)

4b9b3361

Ответ 1

В С++ 0x у вас есть простое решение. Я не знаю, реализована ли она в MSVC10.

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

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

Ответ 2

Вы можете использовать что-то вроде этого:

template<class T> class Base {
protected:
   // derived classes must call this constructor
   Base(T *self) { }
};

class Foo : public Base<Foo> {
public:
   // OK: Foo derives from Base<Foo>
   Foo() : Base<Foo>(this) { }
};

class Moo : public Base<Foo> {
public:
   // error: constructor doesn't accept Moo*
   Moo() : Base<Foo>(this) { }
};

class Bar : public Base<Foo> {
public:
   // error: type 'Base<Bar>' is not a direct base of 'Bar'
   Bar() : Base<Bar>(this) { }
};

Ответ 3

template<typename T, int arg1, int arg2>
struct Base
{
    typedef T derived_t;
};

struct Foo : Base<Foo, 1, 2>
{
    void check_base() { Base::derived_t(*this); } // OK
};

struct Bar : Base<Foo, 1, 2>
{
    void check_base() { Base::derived_t(*this); } // error
};

Этот код основан на ответе Amnon, но проверка кода не содержит имени производного класса, поэтому я могу скопировать и вставить его без изменений.

Ответ 4

Нет способа узнать тип вывода. Вы можете применить этот Foo, полученный от Base<Foo>, но вы не можете обеспечить, чтобы из этого не вытекали другие классы.

Ответ 5

Я могу использовать макрос

#define SOMENAMESPACE_BASE(type, arg1, arg2) type : Base<type, arg1, arg2>

но я не хочу использовать макросы, если лучшее решение существует.