无法正确使用这种讨厌的CRTP语法

时间:2016-03-12 18:49:58

标签: c++ templates c++11 crtp

请考虑以下代码:

class A {
    virtual void foo() = 0;
};

template <template <typename... Ts> class SubA, typename... Ts>
class Helper : public A {
    static void bar();
    virtual void foo() override final {
        return bar();
    }
};

template <typename T>
class NiceA : Helper<NiceA, T> {    };

这个编译。 修改:如果我现在添加:

template <>
void Helper<NiceA, int>::bar()
{
    std::cout << "Hi." << std:: endl;
}

这个显式实例化编译。但如果我改为添加:

template <typename T>
void Helper<NiceA, T>::bar()
{
    std::cout << "Hi." << std:: endl;
}

失败并出现错误:

a.cpp:22:28: error: invalid use of incomplete type ‘class Helper<NiceA, T>’
 void Helper<NiceA, T>::bar()
                            ^
a.cpp:10:7: error: declaration of ‘class Helper<NiceA, T>’
 class Helper : public A {
       ^

为什么?

注意:使用gcc 4.9.3进行编译。

2 个答案:

答案 0 :(得分:3)

首先,请注意这与CRTP无关,即它与从NiceA继承的Helper无关。此外,它与继承自Helper的{​​{1}}或该虚函数无关。

因此,这是问题的实际代码:

A

只是说,因为通过提供MCVE,您可以让那些想要回答的人更轻松地完成工作。

现在,为什么不编译?您不能部分专门化单个成员函数。周期。

你需要对整个班级进行部分专业化。

template <template <typename... Ts> class SubA, typename... Ts>
class Helper
{
  static void bar();
};

template <typename T>
class NiceA
{
};

template <>  // This compiles fine
void Helper<NiceA, int>::bar()
{
}

template <typename T>  // This does not
void Helper<NiceA, T>::bar()
{
}

int main()
{
}

答案 1 :(得分:2)

你只是错误地定义了你的成员函数:

template <typename T>
void Helper<NiceA, int>::bar()
{
    std::cout << "Hi." << std:: endl;
}

这将是bar<T>()中函数模板Helper<NiceA, int>的定义。但bar()只是一个普通函数,因此您无需指定任何模板参数:

template <> // <== nothing
void Helper<NiceA, int>::bar()
{
    std::cout << "Hi." << std:: endl;
}

Clang的错误在这个特定的例子中更有用:

main.cpp:19:1: error: template parameter list matching the non-templated nested type 'Helper<NiceA, int>' should be empty ('template<>')
template <typename T>
^        ~~~~~~~~~~~~