我可以在 lambda 中使用 constexpr 值而不捕获它吗?
Posted
技术标签:
【中文标题】我可以在 lambda 中使用 constexpr 值而不捕获它吗?【英文标题】:Can I use a constexpr value in a lambda without capturing it? 【发布时间】:2016-02-25 17:18:47 【问题描述】:我想在 lambda 中使用 constexpr 值。阅读答案 Using lambda captured constexpr value as an array dimension,我认为以下应该可行:
#include<array>
int main()
constexpr int i = 0;
auto f = []
std::array<int, i> a;
;
return 0;
但是,Clang 3.8(带有 std=c++14)抱怨
变量 'i' 不能在 lambda 中隐式捕获,没有 指定默认捕获
这应该被认为是 clang 3.8 中的一个错误吗?
顺便说一句:
上面的代码可以用 gcc 4.9.2 编译。 如果我将 lambda 表达式更改为显式捕获:
...
auto f = [i]
...
clang 3.8 编译它,但 gcc 4.9.2 失败:
错误:‘i’的值在常量表达式中不可用 ...
【问题讨论】:
[constexpr int _i =i]
有什么不同吗?
不,在 gcc 4.9.2 和 Clang 3.8 下都不能编译。
hmmm.... 我猜你认为 #define 作为(临时)解决方案?
但是宏是邪恶的!另外,它们不能用 constexpr 函数赋值。
@GuillaumeRacicot:这只是一个口头禅。从这里引用:***.com/questions/14041453/…“宏就像任何其他工具一样 - 用于谋杀的锤子不是邪恶的,因为它是一把锤子。人们以这种方式使用它的方式是邪恶的。如果你想锤钉子,锤子是完美的工具。”
【参考方案1】:
这应该被认为是 clang 3.8 中的一个错误吗?
是的。仅当 [expr.prim.lambda]/12 要求时才需要捕获:
请特别注意突出显示的示例。 f(x)
不需要捕获 x
,因为它不是 odr 使用的(重载分辨率选择带有 object 参数的重载)。同样的论点适用于您的代码 - [basic.def.odr]/3:
变量
x
,其名称显示为潜在评估表达式ex
被ex
odr 使用 除非应用左值到右值的转换 (4.1) 到x
产生一个不调用的常量表达式 (5.20) 任何重要的功能……
这个要求肯定满足。
...并且,如果
x
是一个对象,ex
是一个元素 表达式e
的一组潜在结果,其中 左值到右值转换 (4.1) 应用于e
,或者e
是 丢弃值表达式(第 5 条)。
i
是其根据 [basic.def.odr]/(2.1) 的一组潜在结果,并且当它传递给对象类型的非类型模板参数时,确实会立即应用 ltr 转换。
因此,正如我们已经证明 (12.1) 不适用 - 而 (12.2) 显然也不适用 - Clang 拒绝您的 sn-p 是错误的。
【讨论】:
该标准似乎并没有在 lambdas 中使用 constexpr 花费太多文字......示例中的代码仅处理运行时使用(对吗?),并且在 clang 3.8 和g++ 4.9.2. 无论如何,在clang中确实看起来是错误的。我提交了错误llvm.org/bugs/show_bug.cgi?id=25627 . @OlafBooij 关键是它不能作为运行时(=odr-)使用,因为没有捕获变量。它编译的事实是......不言自明,因为它的目的是,开发人员甚至可能已经用那个确切的例子测试了东西。 唉,MSVC,在 C++11 之后整整十年,仍然没有编译器可以正确实现它; MSVC 坚持明确捕获i
。以上是关于我可以在 lambda 中使用 constexpr 值而不捕获它吗?的主要内容,如果未能解决你的问题,请参考以下文章
Visual Studio 2015 在 constexpr 中使用 lambda
我可以将 C++17 无捕获 lambda constexpr 转换运算符的结果用作函数指针模板非类型参数吗?
使用 lambda 捕获的 constexpr 值作为数组维度