Consider the following program:
template<typename T>
constexpr int f()
{
T{}.i; // error if instantiated with [T = double]
return 42;
}
constexpr void g(char);
using U = decltype( g( {f<double>()} ) );
To my understanding, the last line is an error because the call to f<double>()
is within a brace initializer, and even though f<T>
returns an int
, the value of the returned int
is needed to decide if it can be narrowed to a char
as expected by g
. This requires the definition of f
to be instantiated with double
, which causes an error. Both gcc and clang reject this code.
However, if the definition of g
is changed to accept an int
parameter:
constexpr void g(int);
then it seems that there is no need to instantiate the definition of f
, since the narrowing conversion must succeed. Indeed, gcc accepts this, but clang still instantiates f
with double
and rejects the code. Additionally, if f
is only declared, but not defined, clang accepts the code, which implies that the definition is not needed, and shouldn't be instantiated.
Is my reasoning correct, and this is a clang bug, or is instantiation required, and this is actually a gcc bug?
This is CWG #1581 I think, resolved by P0859.
temp.inst/5 says:
Unless a function template specialization is a declared specialization, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist or if the existence of the definition affects the semantics of the program.
Does the existence affect the semantics of the program?
temp.inst/8 says:
The existence of a definition of a variable or function is considered to affect the semantics of the program if the variable or function is needed for constant evaluation by an expression ([expr.const]), even if constant evaluation of the expression is not required or if constant expression evaluation does not use the definition.
Is it needed for constant evaluation by an expression?
expr.const/15.6-7 says:
A function or variable is needed for constant evaluation if it is:
- a constexpr function that is named by an expression that is potentially constant evaluated, or
- a variable whose name appears as a potentially constant evaluated expression that is either a constexpr variable or is of non-volatile const-qualified integral type or of reference type.
Is it named by an expression that is potentially constant evaluated?
expr.const/15.1-15.5 says:
An expression or conversion is potentially constant evaluated if it is:
- a manifestly constant-evaluated expression,
- a potentially-evaluated expression,
- an immediate subexpression of a braced-init-list,
- an expression of the form & cast-expression that occurs within a templated entity, or
- a subexpression of one of the above that is not a subexpression of a nested unevaluated operand.
It is an immediate subexpression of a braced-init-list.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With