通用的lambda及其作为恒定表达的论点
Generic lambda and its argument as constant expression
以下代码被GCC 7.2和Clang 5.0.0接受,但被Microsoft vs 2017拒绝15.5.0 Preview 5和Intel C 编译器19:
struct S { };
constexpr int f(S)
{
return 0;
}
int main()
{
auto lambda = [](auto x)
{
constexpr int e = f(x);
};
lambda(S{});
}
Microsoft:
<source>(12): error C2131: expression did not evaluate to a constant
英特尔:
<source>(12): error: expression must have a constant value
constexpr int e = f(x);
^
<source>(12): note: the value of parameter "x" (declared at line 10) cannot be used as a constant
constexpr int e = f(x);
^
如果我用f(decltype(x){})
替换f(x)
,Microsoft和Intel都不会抱怨。我知道x
不是恒定的表达式,而是在f
中使用。这可能就是GCC和Clang不抱怨的原因。
我想Microsoft和Intel编译器在拒绝此代码方面是正确的。你怎么看?
来自[expr.const]:
表达式E是A 核心常数表达式,除非遵循e的评估E遵循抽象机器的规则,将评估以下表达式之一:
[...]
除非将其应用于
,否则
- 积分或枚举类型的非易失性glvalue,它是指具有前面初始化的完整的非挥发性const对象,以恒定表达式初始化,或者
- 一个非易失性的glvalue,它是指字符串的子对象,或
- 是指使用ConstexPR定义的非易失性对象,或者是指该对象的不可弹性子对象,或
- 字面类型的非易失性glvalue是指非易失性物体,其寿命开始于评估e;
[...]
在f(x)
中,我们在x
上进行lvalue-to-rvalue转换。x
不是积分或枚举类型,它不是字符串字符TER的子对象,它不是由ConstexPR定义的对象,其寿命不是从评估f(x)
开始的。
似乎使这不是核心常数表达式。
但是,正如Casey指出的那样,由于S
是空的,因此其隐式生成的复制构造函数实际上不会触发此lvalue to-rvalue转换。这意味着该表达式中没有什么实际上违反了任何核心恒定表达限制,因此GCC和Clang在接受它时是正确的。这种解释对我来说似乎是正确的。constexpr
很有趣。
这不是gcc/clang错误。具有模板函数的C 11中可以复制相同的行为:
template <typename T>
void foo(T x)
{
constexpr int e = f(x);
}
int main()
{
foo(S{});
}
在Godbolt.org上
问题是...
template <typename T>
void foo(T x)
{
constexpr int e = f(x);
}
... f(x)
是常数表达式吗?
来自[expr.const]:
表达式
e
是核心常数表达式,除非遵循摘要计算机的e
的评估将评估以下表达式之一:
constexpr
构造函数以外的函数的调用,constexpr
函数或琐碎驱动器的隐式调用
S{}
和 0
是常数表达式,因为它不会违反[expr.const]中的任何规则。f(x)
是一个恒定的表达式,因为它是对constexpr
函数的调用。
除非我缺少某些东西,否则GCC和Clang在这里是正确的。
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 可组合的lambda/std::函数与std::可选
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 如何将lambda作为模板类的成员函数参数
- C++从其他 constexpr 创建 lambda 不能按顺序执行 Constexpr
- 在 lambda 捕获中声明的变量的类型推导
- 我可以将调用类的"this"传递给 lambda 函数吗?
- 为什么lambda在clang上崩溃而不是在gcc上崩溃
- 模板函数指针和lambda
- 两组使用lambda函数的大括号
- 使lambda不可复制/不可移动
- FLTK:按下哪个按钮 - 将数字传递给按钮的回调 (lambda)
- 尝试将lambda函数放在队列中时出现一般分配器错误(可能是与unique_ptr有关的错误)
- 将带有unique_ptr的可变 lambda 传递给 const&std::function
- AWS Lambda C++运行时权限被拒绝
- 捕获lambda中的std::数组
- 这 4 个 lambda 表达式之间有什么区别?
- 在实现文件中使用头文件的通用 lambda
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?