为什么lambda无法从到达范围捕获类型const double而是const int是? [英] Why type const double is not captured by lambda from reaching-scope, but const int is?

查看:100
本文介绍了为什么lambda无法从到达范围捕获类型const double而是const int是?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎不明白为什么编译以下类型为const int的代码:

I seem can't understand why the following code with type const int compiles:

int main()
{
  using T = int;
  const T x = 1;
  auto lam = [] (T p) { return x+p; };
}
$ clang++ -c lambda1.cpp  -std=c++11
$

而此类型为const double的类型则不会:

while this one with type const double doesn't:

int main()
{
  using T = double;
  const T x = 1.0;
  auto lam = [] (T p) { return x+p; };
}
$ clang++ -c lambda2.cpp  -std=c++11
lambda1.cpp:5:32: error: variable 'x' cannot be implicitly captured in a lambda with no capture-default specified
  auto lam = [] (T p) { return x+p; };
                               ^
lambda1.cpp:4:11: note: 'x' declared here
  const T x = 1.0;
          ^
lambda1.cpp:5:14: note: lambda expression begins here
  auto lam = [] (T p) { return x+p; };
             ^
1 error generated.

但是使用constexpr double编译:

yet compiles with constexpr double:

int main()
{
  using T = double;
  constexpr T x = 1.0;
  auto lam = [] (T p) { return x+p; };
}
$ clang++ -c lambda3.cpp  -std=c++11
$

为什么int的行为不同于double,或除int以外的任何其他类型,即const限定符接受int,而double / other类型必须是constexpr?同样,为什么这段代码可以用C ++ 11编译,我从[1]的理解是这种隐式捕获是C ++ 14的功能。

Why behaviour for int differs from double, or for any other type than int, i.e. int is accepted with const qualifier, yet double/other types must be constexpr? Also, why this code compiles with C++11, my understanding from [1] is that such implicit captures is C++14 feature.

.. [1]

推荐答案

原因为何?捕获列表为空的lambda如何能够引用到达范围名称?这最终是为了维护C ++ 03兼容性,因为在C ++ 03中,用常量表达式初始化的const整数或const枚举类型可用于常量表达式,但对于浮点数则不是这种情况。

The reason for this ends up being to maintain C++03 compatibility since in C++03 const integral or const enumeration types initialized with a constant expression were usable in a constant expression but this was not the case for floating point.

可以在在C ++ 11之后出现的缺陷报告1826 解释了ABI中断注释)并询问(强调矿山):

The rationale for keeping the restriction can be found in defect report 1826 which came after C++11(this explains the ABI break comment) and asks (emphasis mine):


已初始化的const整数可以在常量表达式中使用带有常量的变量,但是不能使用常量初始化的const浮点变量。 这是有意的,与C ++ 03兼容,同时鼓励始终使用constexpr 。但是,有人发现这种区别令人惊讶。

A const integer initialized with a constant can be used in constant expressions, but a const floating point variable initialized with a constant cannot. This was intentional, to be compatible with C++03 while encouraging the consistent use of constexpr. Some people have found this distinction to be surprising, however.

还观察到,允许将const浮点变量用作常量表达式将是ABI突破性的更改,因为它将影响lambda捕获。

一种可能是不建议在常量表达式中使用const积分变量。

One possibility might be to deprecate the use of const integral variables in constant expressions.

的响应是:


CWG认为不应更改当前规则,并且程序员希望使用浮点值来参与常量表达式

CWG felt that the current rules should not be changed and that programmers desiring floating point values to participate in constant expressions should use constexpr instead of const.

我们可以注意到,这个问题指出了允许 const浮点数为常量表达式

We can note that the question points out that allowing const floating point variables to be constant expression would be an ABI-break with respect to lambda capture.

之所以如此,是因为lambda不需要捕获变量(如果未使用odd且允许使用const浮点变量),则无需捕获固执己见

This is the case since a lambda does not need to capture a variable if it is not odr-used and allowing const floating point variables to be constant expressions would allow them to fall under this exception.

这是因为使用常量表达式或constexpr文字类型初始化的const整数或枚举类型的左值到右值转换是以常量表达式允许。对于使用常量表达式初始化的const浮点类型,不存在此类异常。 C ++ 11标准草案草案 [expr.const]中对此进行了介绍p2

This is because an lvalue-to-rvalue conversion of a const integer or enumeration type initialized with a constant expression or a constexpr literal type is allowed in a constant expression. No such exception exists for const floating point types initialized with a constant expression. This is covered in the draft C++11 standard section [expr.const]p2:


条件表达式是一个核心常量表达式,除非它涉及以下内容之一作为可能的
评估的子表达式[ ...]

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression [...]

并包含在 [expr.const] p2.9



  • 左值-rvalue转换(4.1),除非将其应用于

    • 整数或枚举类型的glvalue,该整数或枚举类型引用具有先前初始化的已初始化$ b $的非易失性const对象b具有常量表达式,或者

    • 文字类型的glvalue引用用constexpr定义的非易失性对象,或者引用这样的
      的子对象对象,或

Changi如果它们不再必须捕获非奇数使用的const浮点值(这是ABI中断),则这可能会影响lambda对象的大小。此限制最初是为了保持C ++ 03兼容性并鼓励使用constexpr而设置的,但现在已经存在此限制,很难将其删除。

Changing this would potentially effect the size of a lambda object if they no longer had to capture non-odr-used const floating point values which is an ABI break. This restriction was originally put in place to keep C++03 compatibility and to encourage the use of constexpr but now this restriction is in place it becomes hard to remove it.

注意,在C中++ 03 我们仅被允许为const整型或const枚举类型指定类中的常量初始化器。在C ++ 11中,对它进行了扩展,并且允许我们使用大括号或等于初始化器为constexpr文字类型指定常量初始化器。

Note, in C++03 we were only allowed to specify an in class constant-initializer for const integral or const enumeration types. In C++11 this was expanded and we were allowed to specify constant-initializer for constexpr literal types using a brace-or-equal-initializer.

这篇关于为什么lambda无法从到达范围捕获类型const double而是const int是?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆