为何未使用问题成员函数时,C++模板类可成功编译?
为什么不调用模板类中依赖未定义成员的函数时,代码能正常编译?
我原本认为这段代码应该编译失败,因为Exclamator<B>的成员函数f()依赖B类的name成员,但B类并没有提供该成员。但实际情况是,只要不调用xb.f(),哪怕关闭优化选项(-O0),代码依然能正常编译运行,这是为什么?
#include <string> #include <iostream> class A { public: std::string name() { return "A"; } }; class B {} ; template <typename T> class Exclamator { public: Exclamator(T a): x{a} {} void f() { std::cout << x.name() << std::endl; } private: T x; }; int main() { A a; Exclamator xa {a}; xa.f(); B b; Exclamator xb {b}; // xb.f(); return 0; }
编译运行输出:
$ g++ -std=c++17 -O0 main.cpp $ ./a.out A
这是C模板的**延迟实例化(lazy instantiation)**机制导致的,这是C标准明确规定的行为,和编译器优化无关:
- 模板类的成员函数并不是在模板类被实例化(比如创建
Exclamator<B>对象)时就全部生成代码,而是只有当该成员函数被实际调用时,才会被实例化。 - 当你创建
Exclamator<B>对象xb时,只有被用到的成员——也就是构造函数——会被实例化。而Exclamator的构造函数只需要B能被拷贝构造(B有默认的拷贝构造函数),这完全合法,所以编译没问题。 - 成员函数
f()因为被注释掉没有调用,所以编译器不会去实例化它,自然也就不会检查B是否有name()成员。 - 如果你把
xb.f()的注释去掉,编译器就会实例化Exclamator<B>::f(),此时才会发现B没有name()成员,编译就会报错。
内容的提问来源于stack exchange,提问作者Roman Pavelka
相关产品推荐
相关产品推荐

