A question to C++ standard lawyers. My feeling is that the following code should be 100% accepted, but GCC (all versions supporting C++23 including trunk) rejects constructs using trailing return type with dependent names:
#include <utility>
// wraps lvalues by ref and xvalues by move
template <typename T, auto size_>
struct wrap {
T obj;
};
// error in gcc, ok in clang:
template <typename T>
wrap(T && a) -> wrap<T, size(a)>;
// error in gcc, ok in clang:
template <typename T>
auto make_wrap(T && a) -> wrap<T, size(a)> {
return {std::forward<T>(a)};
}
// ok in gcc and clang but requires T to be
// default-constructible:
template <typename T>
auto make_wrap1(T && a) -> wrap<T, size(T{})> {
return {std::forward<T>(a)};
}
// ok in gcc and clang:
template <typename T>
auto make_wrap2(T && a) {
return wrap<T, size(a)>{std::forward<T>(a)};
}
Try it here: https://godbolt.org/z/EdbbWEYoj. The error is:
there are no arguments to 'size' that depend on a template parameter, so a declaration of 'size' must be available [-fpermissive]
Note that make_wrap1
works and the deduction guide would work too in GCC when using size(T{})
instead of size(a)
. But a
clearly depends on the template parameter T
so both should work and Clang accepts everything.
Is it then a bug in GCC?
(For those who want to instantiate any of the above definitions: note that the type template parameter T
needs a definition of a constexpr callable size
that can be called with an argument of type T
)
It's just a confusing error message.
This gcc bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104255 prevents using function parameters outside a function body even though it's well formed. So, -> wrap<T, size(a)>
is actually -> wrap<T, size(<<<ERROR>>>)>
, and apparantly gcc doesn't consider errors to be dependent.
Here's the message for the actual problem further down:
<source>:15:31: error: use of parameter outside function body before ')' token
15 | wrap(T && a) -> wrap<T, size(a)>;
| ^