包含无效成员函数的模板类

时间:2015-05-17 18:01:32

标签: c++ templates c++17

使用不能与某些成员函数一起使用的类来实例化类模板在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中发生变化吗?

2 个答案:

答案 0 :(得分:6)

是的,总的来说。类模板的非虚拟成员函数本身就是函数模板,并且像所有函数模板一样,它们仅在使用时被实例化。因此,如果您从未使用类模板特化的某些成员函数,则成员函数无需对该特化有效。

从C ++ 11开始,标准库实际上充分利用了这种细粒度的实例化控件。容器的类型要求适用于成员函数,而不是整个模板,因此,例如,您可以std::map<K, T> Toperator[]不是默认构造的;你就是不能打电话给JAVA_HOME

请注意,显式类模板实例化会实例化所有成员函数。

答案 1 :(得分:1)

这是标准行为,不会改变。

原因如下:模板是需要使用各种类型参数的通用代码。模板化代码中的某些操作对于一种类型(call_f上的A)可能完全有效,但对另一种类型(call_f上的B)可能非常错误。标准中的决定是允许非敏感的模板代码,例如类型call_f的{​​{1}},只要永远不使用此模板函数(这将触发模板函数的编译)

这样,代码可以是通用的,也是安全的,因为这些检查是在编译时完成的。