Consider the following code:
template <int N, typename T> void f(T) { }
template <typename T>
constexpr int k(T&) { return 0; }
int main()
{
constexpr auto i = 1;
f<k(i)>([&i]
{
f<k(i)>(0);
});
}
clang++
(trunk) compiles it. g++
(trunk) fails with the following error:
<source>: In lambda function: <source>:11:19: error: no matching function for call to 'f<k<const int>((* & i))>(int)' 11 | f<k(i)>(0); | ^ <source>:1:35: note: candidate: 'template<int N, class T> void f(T)' 1 | template <int N, typename T> void f(T) { } | ^ <source>:1:35: note: template argument deduction/substitution failed: <source>:11:19: error: '__closure' is not a constant expression 11 | f<k(i)>(0); | ^ <source>:11:13: note: in template argument for type 'int' 11 | f<k(i)>(0); | ~^~~
live example on godbolt.org
Changing k(T&)
to k(T)
solves the issue. It seems to me that the problem is related to the fact that the reference argument is not a constant expression, but it not used as part of k
.
What compiler is correct here?
GCC is correct here.
According to [expr.const]/4:
An expression
e
is a core constant expression unless the evaluation ofe
, following the rules of the abstract machine, would evaluate one of the following expressions:
- ...
- in a lambda-expression, a reference to [...] a variable with automatic storage duration defined outside that lambda-expression, where the reference would be an odr-use; ...
- ...
k(i)
odr-uses i
thus k(i)
is not a constant expression in the lambda expression, so this code is ill-formed.
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