使用不能与某些成员函数一起使用的类来实例化类模板在C ++中是否合法?
例如:
class A {
public:
void f() { }
};
class B {
};
template<typename T>
class Wrapper {
private:
T t_;
public:
void call_f() { t_.f(); }
};
int main() {
Wrapper<A> a;
Wrapper<B> b;
a.call_f();
}
此代码编译,我可以使用b
,只要我不尝试调用b.call_f()
。 (同样使用template class Wrapper<B>;
显式实例化会导致编译错误,因为它会实例化所有成员函数。)
这可以保证工作还是未定义的行为? 如果是这样,那么随着概念和要求的引入,这将在C ++ 17中发生变化吗?
答案 0 :(得分:6)
是的,总的来说。类模板的非虚拟成员函数本身就是函数模板,并且像所有函数模板一样,它们仅在使用时被实例化。因此,如果您从未使用类模板特化的某些成员函数,则成员函数无需对该特化有效。
从C ++ 11开始,标准库实际上充分利用了这种细粒度的实例化控件。容器的类型要求适用于成员函数,而不是整个模板,因此,例如,您可以std::map<K, T>
T
,operator[]
不是默认构造的;你就是不能打电话给JAVA_HOME
。
请注意,显式类模板实例化会实例化所有成员函数。
答案 1 :(得分:1)
这是标准行为,不会改变。
原因如下:模板是需要使用各种类型参数的通用代码。模板化代码中的某些操作对于一种类型(call_f
上的A
)可能完全有效,但对另一种类型(call_f
上的B
)可能非常错误。标准中的决定是允许非敏感的模板代码,例如类型call_f
的{{1}},只要永远不使用此模板函数(这将触发模板函数的编译)
这样,代码可以是通用的,也是安全的,因为这些检查是在编译时完成的。