GCC accepts this code, Clang and MSVC reject it due to failed static assertion in assert
.
What does the standard say?
https://godbolt.org/z/PKMKzYGsc
template<typename T>
constexpr int assert() {
static_assert(sizeof(T) == 1);
return 1;
}
template<auto I>
using Int = int;
template<typename T> requires (sizeof(T) == 1)
constexpr auto foo(T) -> Int<assert<T>()> {
return 1;
}
template<typename T> requires (sizeof(T) > 1)
constexpr auto foo(T a) -> Int<1> {
return 2;
}
static_assert(foo('1') == 1);
static_assert(foo(2) == 2);
Clang output:
<source>:3:19: error: static assertion failed due to requirement 'sizeof(int) == 1'
3 | static_assert(sizeof(T) == 1);
| ^~~~~~~~~~~~~~
<source>:11:30: note: in instantiation of function template specialization 'assert<int>' requested here
11 | constexpr auto foo(T) -> Int<assert<T>()> {
| ^
<source>:21:15: note: while substituting deduced template arguments into function template 'foo' [with T = int]
21 | static_assert(foo(2) == 2);
| ^
<source>:3:29: note: expression evaluates to '4 == 1'
3 | static_assert(sizeof(T) == 1);
4
The program is well-formed and gcc is correct in accepting the code as explained below.
From over.over:
All functions with associated constraints that are not satisfied ([temp.constr.decl]) are eliminated from the set of selected functions.
If more than one function in the set remains, all function template specializations in the set are eliminated if the set also contains a function that is not a function template specialization.
Any given non-template function F0 is eliminated if the set contains a second non-template function that is more constrained than F0 according to the partial ordering rules of [temp.constr.order].
Any given function template specialization F1 is eliminated if the set contains a second function template specialization whose function template is more specialized than the function template of F1 according to the partial ordering rules of [temp.func.order].
After such eliminations, if any, there shall remain exactly one selected function.
(emphasis mine)
This means that for the call foo(2)
, the version #1
with sizeof(T)==1
will be eliminated from the set of selected functions. And the other one(version #2
) that satisfies the constraint will be the only viable candidate and used.
12