【问题标题】:Constexpr variable captured inside lambda loses its constexpr-ness在 lambda 中捕获的 constexpr 变量失去了它的 constexpr-ness
【发布时间】:2019-08-03 19:21:59
【问题描述】:

此代码在 g++ (coliru) 中编译得很好,但在 MSVC 中编译得不好(godbolt 和我的 VS2017)。

#include <type_traits>
#include <iostream>
template<class T> void f(){
    constexpr bool b=std::is_same_v<T,int>; //#1
    auto func_x=[&](){
        if constexpr(b){ //#error
        }else{
        }
    };
    func_x();
}
int main(){
    f<int>();
}

(6):错误 C2131:表达式未计算为常量
(6):注意:失败是由于在其生命周期之外读取变量引起的
(6): 注意:见'this'的用法

哪一个(g++ 或 MSVC)错了?
查看'this'的用法”中的this是什么??

如何在保持编译时保证的同时解决它?

在我的真实案例中,b (#1) 是一个复杂的语句,取决于其他一些 constexpr 变量。

【问题讨论】:

  • Coliru 使用 GCC 8.2; gcc.godbolt.org 的 GCC 8.3 也拒绝该代码。 Clang 7.0.0 编译它。

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


【解决方案1】:

GCC 是对的。 b(作为constexpr 变量)实际上不需要是captured

lambda 表达式可以读取变量的值而无需捕获 它如果变量

  • 是 constexpr,没有可变成员。

GCC LIVE

如果让bstatic 看起来,MSVC 可以在不捕获的情况下访问b

template<class T> void f(){
    constexpr static bool b=std::is_same_v<T,int>;
    auto func_x=[](){
        if constexpr(b){
        }else{
        }
    };
    func_x();
}

MSVC LIVE

还有

如何在保持编译时保证的同时解决它?

我们不能为捕获的变量保留 constexpr-ness。它们成为 lambda 闭包类型和 non-static data members can't be constexpr 的非静态数据成员。

【讨论】:

  • 在 C++ 标准中是否有说明这一点的位置?
  • 确实,C++17 似乎是directly contradict thisb 被 lambda 隐式捕获;没有关于成为常量表达式的警告。
  • @NicolBolas 因为bconstexpr,直接对其执行左值到右值的转换并不构成odr 使用。有关标准参考,请参阅 [basic.def.odr]/3。
【解决方案2】:

如何在保持编译时保证的同时解决它?

constexpr bool 标记为static 作为一种解决方法。

Demo

或者,您可以使用if constexpr 中的条件,而不是将其分配给bool。如下:

if constexpr(std::is_same_v<T,int>)

Demo

请注意,关于 lambda 表达式的 constexpr 已针对 MSVC 提出了错误。
其中之一是:problems with capturing constexpr in lambda
另一个是:if constexpr in lambda

【讨论】:

    猜你喜欢
    • 2021-03-21
    • 1970-01-01
    • 2018-10-19
    • 2015-05-04
    • 1970-01-01
    • 2020-10-08
    • 1970-01-01
    • 2016-02-25
    相关资源
    最近更新 更多