这个问题Access to constexpr variable inside lambda expression without capturing回答了为什么以下示例中的ref-capture不是严格必要的。但另一方面,如果被捕获,则会收到错误。
错误似乎是由foo()
的递归特性引发的。
template<typename T>
constexpr int bar(const T& x) { // NOK
//constexpr int bar(T x) { // OK
return x;
}
template<typename T>
int foo(const T& l) {
constexpr auto x = l() - 1;
auto y = [&]{return bar(x);}; // if ref-capture is used, the above bar(const T&) is NOK, why?
if constexpr(x <= 0) {
return 42;
}
else {
return foo(y);
}
}
auto l2 = []{
return 3;
};
int main() {
foo(l2);
}
答案 0 :(得分:6)
如果我们使用clang作为编译器,在语言律师方面通常比gcc更相关,我们发现一个简单的例子非常有说服力:
template<typename T>
int foo(T/*&*/ l) {
constexpr auto x = l() - 1;
if constexpr(x <= 0) {
return 42;
}
else {
return 0;
}
}
auto l2 = []{
return 3;
};
int main() {
foo(l2);
}
在foo()
签名中添加和删除引用会使程序编译或编译。我相信,这与关于cppreference的常量表达主题的子弹12有关:
一个id-expression,指向一个变量或一个数据成员 引用类型,除非使用常量表达式初始化或其生命周期在此表达式的评估中开始
https://en.cppreference.com/w/cpp/language/constant_expression
所以这两个陈述似乎都不满意,因为参考文献没有用常量表达式初始化,并且它的生命周期并没有从表达式的评估开始。