struct Value {
using a_type = int;
a_type f() { return 1; }
};
template<typename T>
struct Wrapper {
T t;
auto call_f() { return t.f(); }
};
int main() {
Wrapper<Value> w;
Wrapper<int> w2;
w.call_f();
}
这对Clang和GCC很好。即使Wrapper<int>
的返回类型无法推断(没有Wrapper<int>::call_f()
),int::f()
也会被实例化。只有在w2.call_f()
被调用时它才会失败。
这是C ++标准的一部分,是否可以在所有编译器上运行?
答案 0 :(得分:11)
是的,这是C ++标准的一部分。
模板实例化的规则冗长而复杂,但简短版本是模板类的成员函数仅在需要时实例化。如果没有任何东西调用它,或者尝试获取它的指针,或者显式地实例化它(可能还有其他一些我忘记的情况),那么它就不会被实例化并且你的代码格式正确。
正如@dyp指出的那样,只有在实例化类定义([temp.inst]/1
)时实例化的成员函数的声明,但只返回返回类型推导函数定义实例化时([dcl.spec.auto]/12
)。
这对于最小化模板的开销和对类型要求的许可非常有帮助。正是这个功能可以让你做到这样的事情:
struct Foo {
//no default constructor
Foo(int);
};
std::vector<Foo> foos;
某些std::vector
函数(例如resize
)要求T
是默认构造的,但只要您不调用这些函数,您仍然可以使用其他功能std::vector
。
答案 1 :(得分:2)
是的,它符合标准。 Wrapper<T>::call_f()
只有在被调用时才会被隐式实例化。
$14.7.1/2 Implicit instantiation [temp.inst]:
除非已明确实例化或明确专门化类模板或成员模板的成员,否则在需要成员定义存在的上下文中引用特化时,将隐式实例化成员的特化;
$14.7.1/8 Implicit instantiation [temp.inst]:
实现不应隐式实例化函数模板,变量模板,成员模板,非虚拟成员函数,成员类,类模板的静态数据成员或constexpr if语句的子语句( [stmt.if]),除非需要这样的实例化。