关于C++:奇怪的重复模板变化

Curiously recurring template - variation

关于CRP,如果我想实现它的微小变化(使用模板模板参数),我会得到一个编译错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template <template <typename T> class Derived>
class Base
{
public:
    void CallDerived()
    {
        Derived* pT = static_cast<Derived*> (this);
        pT->Action(); // instantiation invocation error here
    }
};

template<typename T>
class Derived: public Base<Derived>
{
public:
    void Action()
    {
    }
};

我不确定是否有人会选择这个表单(不是为我编译的)而不是使用这个表单(这是可行的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template <typename Derived>
class Base
{
public:
    void CallDerived()
    {
        Derived* pT = static_cast<Derived*> (this);
        pT->Action();
    }
};

template<typename T>
class Derived: public Base<Derived<T>>
{
public:
    void Action()
    {
    }
};


这也应该编译。我们只需要显式地指定另一个模板参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 template <typename T, template <typename T> class Derived>
 class Base
 {
 public:
     void CallDerived()
     {
        Derived<T>* pT = static_cast<Derived<T>*> (this);
        pT->Action(); // instantiation invocation error here
     }
 };

template<typename T>
class Derived: public Base<T,Derived>
{
public:
    void Action()
    {
    }
};


在第一个示例中,类模板实际上采用模板模板参数,而不仅仅是模板参数,正如您所写:

1
2
3
4
5
template <template <typename T> class Derived>
class Base
{
     //..
};

所以这个代码没有意义:

1
2
Derived* pT = static_cast<Derived*> (this);
pT->Action(); // instantiation invocation error here

这里,Derived是一个模板参数,它需要模板参数,而您没有提供给它。事实上,在CallDerived()函数中,您无法知道需要为其提供的类型,以便执行您打算执行的操作。

第二种方法是正确的解决方案。用它。