考虑一些函数模板,例如:
template <class T>
const auto& foo() { static T t; return t; }
如果 T
则定义无效应该是 void
.尽管如此,我们可以单独实例化声明而不触发错误:extern template const auto& foo<void>(); // explicit instantiation declaration
现在让我们考虑 foo
的情况。被调用,而不是被显式实例化。显然,如果 foo
曾经在评估的上下文中调用,特化的定义将被实例化。在未经评估的情况下呢?我们知道,如果在未计算的上下文中调用具有非推导返回类型的函数模板,则不会实例化特化的定义。最明显的例子是 std::declval<T>
.尚不清楚对于具有推导返回类型的函数是否可以这样做。例如,我考虑过这个:
static_assert(sizeof( (void)foo<void>(), char{} ) == 1);
然而,即使在这种情况下,编译器肯定有足够的信息来评估 sizeof
在不知道返回类型的情况下,仍然会出现编译错误(godbolt link)。foo<void>
的定义在这个情况下? foo<void>
可以在不会实例化其定义的未评估表达式中调用吗? 最佳答案
What provision of the Standard requires the instantiation of the definition of
foo<void>
in this situation?
[dcl.spec.auto]/11 中的注释尽管是非规范性的确实提到任何特殊化的使用(在其声明的返回类型中具有占位符的函数模板)将导致隐式实例化 [extract, 重点矿]:
[...] [ Note: Therefore, any use of a specialization of the function template will cause an implicit instantiation.
而且,[dcl.spec.auto]/14涵盖了允许显式实例化声明而不触发实例化的特殊情况,同时也暗示了为确定函数模板的返回类型而触发的实例化机制与“常规”实例化机制有些分离[]重点矿]:
An explicit instantiation declaration does not cause the instantiation of an entity declared using a placeholder type, but it also does not prevent that entity from being instantiated as needed to determine its type. [ Example:
template <typename T> auto f(T t) { return t; } extern template auto f(int); // does not instantiate f<int> int (*p)(int) = f; // instantiates f<int> to determine its return type, but an explicit // instantiation definition is still required somewhere in the program
— end example ]
其中示例的注释(非规范性)指出,这种特殊情况触发的隐式实例化仅用于返回类型推导,并且不放弃在其他地方显式实例化定义的需要。
Is there any way that
foo<void>
can be called inside an unevaluated expression that would not instantiate its definition?
鉴于上述讨论,我会说:不。即使在未评估的表达式中调用也将属于(非规范)“任何使用”。
关于c++ - 如果函数模板已经推断出返回类型,有没有办法在不实例化定义的情况下调用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64915753/