请考虑以下代码:
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进行编译。
答案 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>
^ ~~~~~~~~~~~~