考虑以下代码:
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++
(树干)对其进行编译。 g++
(树干)失败,并显示以下错误:
<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); | ~^~~
将k(T&)
更改为k(T)
可解决此问题。在我看来,该问题与引用参数不是常量表达式,但没有用作k
的一部分有关。
什么编译器在这里正确?
答案 0 :(得分:6)
这里的GCC是正确的。
表达式
e
是核心常量表达式,除非求值 遵循抽象机规则的e
的 以下表达式之一:
- ...
- 在 lambda-expression 中,对变量的引用,该变量具有在 lambda-expression 之外定义的自动存储持续时间, 凡该提述将作单一用途; ...
- ...
k(i)
会使用i
,因此k(i)
在lambda表达式中不是常量表达式,因此该代码格式错误。
答案 1 :(得分:0)
出现在lambda表达式复合语句中但不在表达式外部的表达式k(i)
发出错误。这是一个GCC错误。根据{{3}}
lambda表达式的复合语句中的 id-expression 是对引用捕获的引用的odr-use的odr-使用,指的是捕获的引用绑定到的实体,而不是捕获的参考。
因此,lambda外部的k(i)
与lambda外部的k(i)
是相同的表达式,因此GCC没有理由针对第二个表达式而不是第一个表达式发出错误。
答案 2 :(得分:-1)
编译时出现0个错误。
我使用了变量result_k = k(i);
来绕过此错误。
template <int N, typename T> void f(T) { }
template <typename T> constexpr int k(T&) { return 0; }
int main() {
constexpr auto i = 1;
const int result_k=k(i);
f<result_k>([&i]{ f<result_k>(0);});
}