Consider the minimal example:
template <int>
struct bar { };
int main()
{
[](auto i) -> bar<i> { return {}; };
}
Or even:
template <int>
struct bar {};
template <class I>
auto foo(I i) -> bar<i> {}
clang compiles both forms without problems but gcc find the usages invalid (ex. 1), (ex. 2)
The question might look silly however the type of parameter can have the constexpr conversion operator overloaded (in this case type of i
deduced from value passed to lambda/foo to int
in constexpr manner) and in this scenario it would be quite convenient not to be forced to do some workarounds to access it directly...
This seems like a gcc
bug. I reported it as issue #80242.
gcc
complains about the validity of i
as a template argument:
error: template argument 1 is invalid
I've followed the C++ grammar from trailing-return-type
to template-argument
, which needs to be a constant-expression
:
template-argument:
- constant-expression <-
- type-id
- id-expression
The real question then becomes: "is i
a valid constant-expression
?".
I think the answer is "yes", because §8.20.4 [expr.const] says:
A converted constant expression of type
T
is an expression, implicitly converted to typeT
, where the converted expression is a constant expression and the implicit conversion sequence contains only:
- user-defined conversions,
[...]
(Note: Such expressions may be used in new expressions, as case expressions, as enumerator initializers if the underlying type is fixed, as array bounds, and as non-type template arguments. )
There is a sequence of implicit conversions that, starting from i
, will produce a converted constant expression which is a constant expression. Given:
template <int>
struct bar { };
template <class I>
auto foo(I i) -> bar<i> { }
int main()
{
foo(std::integral_constant<int, 1>{}); // (0)
}
In the context of the function call at (0), the argument i
is an instance of std::integral_constant<int, 1>
.
std::integral_constant
provides a constexpr
user-defined conversion to the underlying value_type
.
Converted constant expressions explicitly allow user-defined conversions, as seen above in §8.20.4 [expr.const].
std::integral_constant::operator value_type()
will return the non-type template argument 1
. This is a core constant expression as it doesn't violate any of the rules specified in §8.20.2 [expr.const].
Therefore, the converted constant expression is a constant expression.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With