我很惊讶地发现以下编译:
#include <iostream>
using namespace std;
template<typename T>
class SomeCls {
public:
void UseT(T t) {
cout << "UseT" << endl;
}
};
template<>
class SomeCls<int> {
// No UseT? WTF?!??!?!
};
int main(int argc, char * argv[]) {
SomeCls<double> d;
SomeCls<int> i;
d.UseT(3.14);
// Uncommenting the next line makes this program uncompilable.
// i.UseT(100);
return 0;
}
为什么允许这样做? class SomeCls<int>
不需要void UseT(T t)
方法似乎是错误的。我敢肯定我在这里缺少专业化点(我不是C ++专家)。有人可以赐教我吗?
答案 0 :(得分:11)
因为SomeCls<double>
是与SomeCls<int>
或任何其他SomeCls<T>
完全不同的类型。他们没有任何关系,因此他们可以拥有他们想要的任何成员。请确保不要调用i.UseT()
,这当然是编译器开始抱怨的地方。
答案 1 :(得分:7)
专业化可以专注于您认为合适的任何方式。如果你想省略所有方法,添加或删除基类,添加或删除数据成员那么没关系。
template <class T>
class Foo {};
template <>
class Foo<int> { void extrafunc(); }; //fine
template <>
class Foo<bool> : public ExtraBase {}; // fine
template <>
class Foo<double> { int extradata; }; // fine
当专门化函数时,唯一的限制是参数保持不变(相对于主模板),尽管你可能会超出心脏的内容。
template <class T>
void foo(const T&);
template <>
void foo<int>(int); // not fine, must be const int&
void foo(int); // fine, this is an overload, not a specialisation
template <class T>
void foo(T*); // fine, again this is an overload, not a specialisation
答案 2 :(得分:0)
您的代码从不调用UseT的int
版本,因此您无需提供它。
答案 3 :(得分:0)
我已将答案标记为“正确”, 但我真的不满意。我不是 询问它是如何工作的;我问为什么 就是这样设计的。它的方式 作品不会让我觉得一致 与OO。它甚至看起来一致。 为什么功能模板 专业化有限制 接口必须一致, 而类模板专业化 不是吗?
如果这是你的问题,那么你可能应该这样说。
我将从最后一点开始:为什么函数需要相同的签名。这很容易,函数已经有办法通过重载重用名称。
int f(int);
double f(double); //no templates needed
允许专门化来更改函数的签名会不必要地使已经很困难的名称解析过程复杂化,而不会实际提供任何其他功能。
对于类类型,模板要复杂得多。您不仅需要考虑成员函数,还有成员对象,typedef,嵌套类型等。专业化专门研究所有。如果SomeTemplatedObject<double>
要求SomeTemplatedObject<T>
一般不需要特定的私人成员,那么如何在不更改“界面”的情况下为SomeTemplatedObject
专门设定double
?或者对某些类型没有意义的方法是什么?或者是否需要修改嵌套类型以保持一致的界面?这甚至都不涉及模板元编程的大问题。
您甚至不需要为一般情况提供完整的类型。
template<typename T>
struct Object;
template<>
struct Object<int> { //what interface does this need?
typedef int type;
};
如果你觉得有必要坚持一些纯粹的OO定义,那么你总是可以自由地不专门化模板而不精确匹配他们的原始布局。