具有未定义成员函数返回类型的模板实例化
Template instantiation with undefined member function return types
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>::call_f()
的返回类型(不存在int::f()
), Wrapper<int>
也会被实例化。只有当w2.call_f()
被调用时才会失败。
这是c++标准的一部分吗?它能在所有的编译器上工作吗?
是的,这是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
的其他功能。
是的,这是由标准保证的。Wrapper<T>::call_f()
只有在被调用时才会被隐式实例化。
$14.7.1/2隐式实例化[temp.inst]:
除非类模板或成员模板的成员已显式实例化或显式特化,否则当在要求成员定义存在的上下文中引用该特化时,该成员的特化将隐式实例化;
$14.7.1/8隐式实例化[temp.inst]:
实现不应隐式实例化函数模板、变量模板、成员模板、非虚成员函数、成员类、类模板的静态数据成员或constexpr if语句([stmt.if])的子语句,除非需要这样的实例化。
- 对象实例化与类型C++
- 实例化多种类型的成员函数模板
- 实例化不同类型的模板函数
- 如何在实例化类类型的变量时打印其名称
- 从转发函数类型推断的模板化返回类型
- C++ 模板化类定义 - 不同类的模板化返回类型
- 为什么在操纵函数名称中包含C 功能模板实例的返回类型
- 如何防止编译器省略未显式实例化的类型?
- 有没有办法使用显式实例化按类型设置成员变量
- 如何实例化 int 类型的数组对象并在 c++ 中填充它
- 是实例化返回类型还是简单地赋值
- c++外部模板实例化和类型定义(gcc)
- 在c++中实例化派生类型
- 强制实例化派生类型而不是基类型
- 实例化basic_regex类型数组时出错
- 模板化操作符实例化和类型转换
- 在只有模板化返回类型的函数模板中混合模板专门化和enable_if
- 虚拟继承,显式实例化——返回派生类引用/指针(协变类型)
- 哪个编译器是正确的? 'template'在需要模板化返回类型之前?
- C++模板化,传递具有参数化返回类型的函数指针