【问题标题】:Difference between ref-captured and non-explicitly captured constexpr variables in lambda-expressionslambda 表达式中 ref 捕获和非显式捕获的 constexpr 变量之间的区别
【发布时间】:2018-05-09 07:31:06
【问题描述】:

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

【问题讨论】:

  • 如果你在捕获组中放入任何东西([x][&amp;x][&amp;],...),它实际上会发生,它与y不是@987654328有关@ 在某些时候不再存在,所以l() - 1 不是编译时表达式并且编译失败。
  • 使用clang,这两种方式都会产生错误,这对我来说更有意义。我不明白为什么 GCC 在这种情况下认为 l() - 1 是一个常量表达式。
  • 这听起来很奇怪,因为l() - 1 应该真的是constexpr
  • 我认为 clang++ 在这里是错误的。您可以测试,l() - 1main() 中给出带有以下行的 constexpr:constexpr auto z = l2() - 1;
  • @wimalopaan 当foo&lt;decltype(l2)&gt; 被实例化时,参数l 是一个没有用常量表达式初始化的引用。未使用常量表达式初始化的引用不能在常量表达式中使用。

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


【解决方案1】:

如果我们使用 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 表达式 引用类型,除非它是用一个常量表达式初始化的,或者它的生命周期是在这个表达式的求值过程中开始的

https://en.cppreference.com/w/cpp/language/constant_expression

所以这两个语句似乎都不满意,因为引用没有用常量表达式初始化,它的生命周期也不是从表达式的评估开始的。

【讨论】:

  • 您可以将其归结为以下内容:constexpr auto z = 1; auto y = [&amp;]{return bar(z);}; constexpr auto z2 = y(); 使用 ref-capture 无法编译。这就是原因,正如@SergeyA 所说:z 是从 lambda 外部重新初始化的。
猜你喜欢
  • 2015-11-23
  • 1970-01-01
  • 2018-10-19
  • 2017-07-25
  • 1970-01-01
  • 2013-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多