关于c ++:如何在使用CRTP时避免错误?

How to avoid errors while using CRTP?

有时我使用crtp编写这样的代码:

1
2
3
4
5
6
7
8
9
10
11
// this was written first
struct Foo : Base<Foo, ...>
{
   ...
};

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

在我跟踪调试器中的代码并发现在Base中没有使用bar的成员之前,很难理解出哪里出了问题。

如何在编译时显示此错误?

(我使用MSVC2010,所以我可以使用一些C++0x特性和MSVC语言扩展)


在C++ 0x中,你有一个简单的解决方案。但我不知道它是否在MSVC10中实现。

1
2
3
4
5
6
7
8
9
10
template <typename T>
struct base
{
private:
    ~base() {}
    friend T;
};

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


您可以使用如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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) { }
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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的答案,但是检查代码不包含派生类的名称,所以我可以复制粘贴它而不做任何更改。


我可以用宏

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

但如果存在更好的解决方案,我不想使用宏。


无法知道派生类型。可以强制执行从Base派生的Foo,但不能强制其他类也从中派生。