【发布时间】:2013-05-27 01:09:20
【问题描述】:
template<typename T>
struct A{
void method1(){}
};
template<>
struct A<int>{
void method2(){}
};
A<int> 会同时拥有 method1 和 method2 吗?而A<float> 将只有method1 ?
【问题讨论】:
template<typename T>
struct A{
void method1(){}
};
template<>
struct A<int>{
void method2(){}
};
A<int> 会同时拥有 method1 和 method2 吗?而A<float> 将只有method1 ?
【问题讨论】:
@jogojapan 的回答解释了该语言的作用。如果您确实想为特定专业添加新成员,这里有几个解决方法:
template<typename T>
struct A_Base {
void method1() {}
};
template<typename T>
struct A : public A_Base<T> {};
template<>
struct A<int>
: public A_Base<int>
{
void method2() {}
};
现在A<int> 有成员method1 和method2,但A<float> 没有method2。
或者(如果您可以修改主模板)...
#include <type_traits>
template<typename T>
struct A {
void method1() {}
template<int N=0>
auto method2() ->
typename std::enable_if<std::is_same<T, int>::value && N==N>::type
{}
};
template<int N> 和 N==N 部分确保 std::enable_if 具有依赖值,因此在有人实际尝试将 A<T>::method2 与不正确的 T 参数一起使用之前不会抱怨。
而且由于这个问题和答案似乎仍然受到关注,稍后进行编辑以在 C++20 中添加它,您可以简单地这样做:
#include <type_traits>
template<typename T>
struct A {
void method1() {}
void method2() requires std::is_same_v<T, int> {}
};
【讨论】:
A_Base 不是 模板,第一种技术(非 C++11 技术)会起作用吗?也就是说,你能有一个A<int>::A_Base::method2吗?我从 MSVC 中得到一个错误,我以前从未见过这个错误 (C2936)。我不确定它是否不可能,C++03 不可能,或者它是否是 MSVC 限制。
A<int>::A_Base::method1提供一个专门的机构。让我看看能不能找到关于它的讨论。
A_base 的目的不是充当有用的接口,只是帮助声明所需的功能。所以实际上并不期望有人会使用A_base* 或std::unique_ptr<A_base> 等等。
每个特化都会带来一种全新的数据类型(或全新的模板,如果特化只是部分的)。来自标准(C++11):
(第 14.5.5/2 节)每个类模板部分特化是一个不同的模板,应为模板部分特化 (14.5.5.3) 的成员提供定义。
还有:
(§14.5.5.3/1) [...] 类模板部分特化的成员与主模板的成员无关。应定义以需要定义的方式使用的类模板偏特化成员;主模板成员的定义永远不会用作类模板部分特化成员的定义。 [...]
上述内容是在部分特化的上下文中陈述的,但它也适用于显式特化(如您的情况),尽管标准并没有很清楚地说明这一点。
还请注意,您不仅需要在特化中声明您想要的所有成员函数,还需要定义它们(这里,即使是显式特化,标准也非常清楚):
(14.7.3/5) 显式特化类的成员不会从类模板的成员声明中隐式实例化;相反,如果需要定义类模板特化的成员,则其自身应被显式定义。在这种情况下,类模板显式特化的定义应在范围内 在定义成员的位置。显式特化类的定义与生成的特化的定义无关。也就是说,它的成员不需要与生成的特化的成员具有相同的名称、类型等。 [...]
所以,事实上,A<int> 将只有 method2(),而A<float> 将只有 method1() 作为成员。此外,如果您还要在 A<int> 特化中引入 method1(),它不需要与 A<float>::method1() 具有相同的参数类型或返回类型。
请参阅@aschepler 的回答,了解避免为int 案例重写模板定义的可能方法。
【讨论】:
template <> struct A<int> { ... };,而只需在类模板定义之外声明(并定义)您要专门化的方法:A<int>::method1() { ... };。
method1 的专业化来处理 int 案例。如果您真的只需要为int 案例添加一个全新的method2,那么确实需要为int 重写整个模板。根据具体情况,最好将method2 添加到主模板定义但未定义(或让它抛出异常,或放入static_asssert(false,"not implemented");(后者仅适用于C++ 11) )。这样您就可以将 method2 专门用于 int 案例,而无需重写整个模板。
专业化替换通用模板。所以A<int> 将只有method2(),当然A<double> 将只有method1()。
【讨论】:
A<int>、A<double> 和 A<char> 将是三个不相关的类。