类模板按引用传递时是否实例化?哪种编译器行为符合C++标准?
类模板特化按引用传递时的实例化规则与编译器合规性
问题代码示例
template <typename T> class A { public: void foo () const {t->foo();} virtual void fooVirtual() {t->foo();} // MSVC: use of undefined type 'B' protected: T* t; }; class B; // 仅前向声明 const A<B>& get(); // 将在另一翻译单元中定义 void foo(const A<B>& a); // 将在另一翻译单元中定义 int main () { const A<B>& a = get(); foo(a); // MSVC: class template instantiation 'A<B>' being compiled return 0; }
问题解答
合规性结论
Clang和GCC的行为符合C++标准,MSVC的报错不符合标准。
核心规则说明
类模板特化A<B>在按引用传递时不需要被实例化,依据C++标准的以下规则:
- 当模板类型仅作为引用、指针类型使用,或仅被声明而未涉及实例的具体成员访问、对象创建时,无需触发类模板的完全实例化。
- 此代码中,
main函数仅接收A<B>的引用并传递给foo函数(同样是引用传递),全程未访问A<B>的任何成员,也未创建A<B>对象,完全不需要A<B>的完整类型信息。 - 对于虚函数
fooVirtual,标准允许延迟实例化其函数体,直到存在调用该虚函数、需要类的完整类型(如创建对象)等场景时才触发。当前代码没有此类场景,因此无需实例化该虚函数体,自然不会因B仅为前向声明而报错。
MSVC在此场景下过早触发了A<B>的实例化,检查了虚函数体中对B的使用,违反了标准中模板实例化延迟的规则。
内容的提问来源于stack exchange,提问作者m7913d
相关产品推荐
相关产品推荐

