This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-11-11
The status of the following example is not clear:
template <typename T> auto foo(T); // Not defined
template <typename T> struct FooCallable {
template<class U>
static constexpr bool check_foo_callable(...) { return false; }
template<class U, class = decltype(foo(U{})) >
static constexpr bool check_foo_callable(int) { return true; }
static constexpr bool value = check_foo_callable<T>(0);
};
static_assert(FooCallable<int>::value == false, "");
The static_assert causes the evaluation of the default template argument decltype(foo<int>(int{})). However, foo is not defined, leaving it with an undeduced placeholder return type. This situation could conceivably be handled in two different ways. According to 9.2.9.7 [dcl.spec.auto] paragraph 9,
If the name of an entity with an undeduced placeholder type appears in an expression, the program is ill-formed.
This would thus appear to be an invalid expression resulting from substitution in the immediate context of the declaration and thus a substitution failure.
The other alternative would be to treat the presence of an undeduced placeholder type for a function template as satisfying the requirements of 13.9.2 [temp.inst] paragraph 4,
Unless a function template specialization has been explicitly instantiated or explicitly specialized, 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.
and attempt to instantiate foo<int>. That instantiation fails because the definition is not provided, which would then be an error outside the immediate context of the declaration and thus a hard error instead of substitution failure.
CWG 2022-11-10
There is no implementation divergence on the handling of this example.
Possible resolution:
Change in 9.2.9.7.1 [dcl.spec.auto.general] paragraph 11 as follows:
If a variable or function with an undeduced placeholder type is named
by an expression (6.3 [basic.def.odr]), the program is
ill-formed. Once a non-discarded return statement has been seen in a
function, however, the return type deduced from that statement can be
used in the rest of the function, including in other return
statements.
[ Example:
...
template <typename T> auto f(T); // not defined
template <typename T> struct F {
template<class U>
static constexpr bool g(...) { return false; }
template<class U, class = decltype(f(U{})) >
static constexpr bool g(int) { return true; }
static constexpr bool value = g<T>(0);
};
static_assert(F<int>::value == false, "");
-- end example ]