问题
Consider some function template such as:
template <class T>
const auto& foo() { static T t; return t; }
The definition would not be valid if T
were to be void
. Nonetheless, we are allowed to instantiate the declaration alone without triggering an error:
extern template const auto& foo<void>(); // explicit instantiation declaration
Now let's consider situations where foo
is called, rather than being explicitly instantiated. Obviously, if foo
is ever called in an evaluated context, the definition of the specialization will be instantiated. What about in an unevaluated context? We know that if a function template with a non-deduced return type is called in an unevaluated context, the definition of the specialization is not instantiated. The obvious example of this is std::declval<T>
. It's not clear whether the same is possible for a function that has a deduced return type.
For example, I considered this:
static_assert(sizeof( (void)foo<void>(), char{} ) == 1);
However, even in this situation, where the compiler definitely has enough information to evaluate the sizeof
expression without knowing the return type, a compilation error still occurs (godbolt link).
- What provision of the Standard requires the instantiation of the definition of
foo<void>
in this situation? - Is there any way that
foo<void>
can be called inside an unevaluated expression that would not instantiate its definition?
回答1:
What provision of the Standard requires the instantiation of the definition of
foo<void>
in this situation?
Albeit non-normative, the note in [dcl.spec.auto]/11 does mention that any use of a specialization (of a function template with a placeholder in its declared return type) will cause an implicit instantiation [extract, emphasis mine]:
[...] [ Note: Therefore, any use of a specialization of the function template will cause an implicit instantiation.
and, moreover, [dcl.spec.auto]/14 covers the particular case of allowing an explicit instantiation declaration without triggering an instantiation, whilst arguably also hinting that the instantiation mechanisms triggered for determining the return type for a function template are somewhat separated from the "regular" instantiation mechanisms [emphasis mine]:
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 ]
where the comment (non-normative) to the example points out that such a special-case triggered implicit instantiation is only used for return type deduction, and does not waive the need for an explicit instantiation definition elsewhere.
Is there any way that
foo<void>
can be called inside an unevaluated expression that would not instantiate its definition?
Given the discussion above, I would say: no. Calling even within an unevaluated expression would fall under the (non-normative) "any use of".
来源:https://stackoverflow.com/questions/64915753/if-a-function-template-has-deduced-return-type-is-there-a-way-to-call-it-withou