#include <type_traits>
template<class T>
auto f(T x) -> std::enable_if_t<x.size() == 4>;
is valid for Clang and MSVC, but invalid according to GCC. Which is correct? https://godbolt.org/z/q8v4G5vn6
Yes, the above code is well-formed and this is an instance of the GCC bug 80242 you have found.
x
is type-dependent on T
, and x.size()
can be a constant expression for some x
.
A compiler should never dismiss this code as ill-formed before instantiating f
, because x.size()
is possibly a constant expression.
Even if x
is an object that doesn't exist at compile time, we can access its size:
std::array<int, 10> x;
constexpr std::size_t size = x.size();
... and all major compilers accept this, as they should.
The reason why this is okay to write is that .size()
for std::array
never accesses the value or address of the object x
, only the template arguments that std::array
was given.
This means that in your function, if T = std::array<...>
, then x.size()
is a constant expression and should be usable as a template argument for std::enable_if_t
.
The error output for GCC is also totally nonsensical, which further reinforces the idea that this is a compiler bug:
<source>:5:46: error: template argument 1 is invalid
5 | auto f(T x) -> std::enable_if_t<x.size() == 4>;
| ^
<source>:5:46: error: template argument 1 is invalid
<source>:5:46: error: template argument 1 is invalid
<source>:5:46: error: template argument 1 is invalid
<source>:5:46: error: template argument 1 is invalid
<source>:5:16: error: invalid use of template-name 'std::enable_if_t' without an argument list
5 | auto f(T x) -> std::enable_if_t<x.size() == 4>;
| ^~~