Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can calls to member functions of function parameters be used as template arguments?

#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

like image 532
Roland Schulz Avatar asked Sep 16 '25 05:09

Roland Schulz


1 Answers

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>;
      |                ^~~
like image 145
Jan Schultke Avatar answered Sep 18 '25 17:09

Jan Schultke