lambda表达式中ref-captured和非显式捕获的constexpr变量之间的区别

时间:2018-05-09 07:31:07

标签: c++ lambda language-lawyer c++17

这个问题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);
}

1 个答案:

答案 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

所以这两个陈述似乎都不满意,因为参考文献没有用常量表达式初始化,并且它的生命周期并没有从表达式的评估开始。