为什么在未求值的操作数中不允许lambda表达式,但允许在常数表达式的未求值部分中? [英] Why are lambda expressions not allowed in an unevaluated operands but allowed in the unevaluated portions of constant expressions?

查看:146
本文介绍了为什么在未求值的操作数中不允许lambda表达式,但允许在常数表达式的未求值部分中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我们查看草稿C ++标准部分 5.1.2 段落 em>):


lambda表达式的求值导致临时的临时值(12.2)。这个临时被称为闭包对象。 lambda表达式不应出现在未求值的操作数中(第5条)。 [注意:一个闭包对象的行为像一个函数对象(20.8).- end note]


5.19 段落说:


<条件表达式是核心常量表达式,除非包含以下之一作为潜在求值的子表达式(3.2),但逻辑AND(5.14),逻辑OR(5.15),和未评估的条件(5.16)操作不考虑 [...]



- 一个lambda表达式(5.1.2);


那么,为什么在未经赋值的操作数中不允许使用lambda表达式,而在常量表达式的未评估部分中允许使用?



在几种情况下操作类型信息( decltype typeid )不是非常有用,因为每个lambda都有唯一的类型。虽然为什么我们想要允许他们在未经评估的上下文中的常量表达式不清楚,也许允许 SFINAE

解决方案

未评估的操作数排除的核心原因是涵盖在 C ++标准核心语言缺陷报告和已接受的问题#1607 。 Lambdas在模板参数中试图澄清这个限制并在 5.1.2 部分说明限制的意图是:


[...]


由于 costant表达式允许它们在未评估的上下文中,因此问题文档中的当前文字实际上有一个洞。但它并不直接说明这种限制的理由。避免名称调整的愿望突出,并且可以推断避免扩展SFINAE 也是所期望的,因为所提出的解决方案试图收紧限制,即使几个可行的替代方案将允许 SFINAE 5.1.2 段落 2的修改版本如下:


lambda表达式不应出现在模板参数中的未求值操作数(第5条[expr]),中,在别名声明中,在typedef声明中,或在函数声明中或函数模板外的函数体和默认参数[注意:这是为了防止lambdas出现在签名 - 附注] 。 [注意:闭包对象的行为就像一个函数对象(20.10 [function.objects])。 -end note]


此提案已被接受,位于 N3936 em> 查看此回答链接



关于避免使lambda语句作为未经赋值的操作数的原理的更明确的讨论。讨论标题为未经批准的lambda表达式的原理上下文在comp.lang.cpp.moderated 丹尼尔·克吕格勒列出了三个原因:


  1. 可能的 SFINAE 案例的极限扩展


    [...]他们被排除的原因是由于sfinae案例的极端扩展(你为编译器打开了一个Pandora框) [...]



  2. 在许多情况下,它只是无用的,因为每个lambda都有一个唯一的类型,假设的例子给出:

      template< typename T,typename U> func); 
    void g(T,U,decltype([](T x,T y){return x + y;})func);

    g(1,2,[](int x,int y){return x + y;});

    声明和调用中的lambda类型不同( em>),因此这不能工作。


  3. 名称调整成为一个问题,因为一旦你在函数签名中允许一个 lambda ,那么 lambda 的主体也必须被修改。



这是一个非常简单的方法,

If we look at the draft C++ standard section 5.1.2 Lambda expressions paragraph 2 says (emphasis mine going forward):

The evaluation of a lambda-expression results in a prvalue temporary (12.2). This temporary is called the closure object. A lambda-expression shall not appear in an unevaluated operand (Clause 5). [ Note: A closure object behaves like a function object (20.8).—end note ]

and section 5.19 Constant expressions paragraph 2 says:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered [...]

and has the following bullet:

— a lambda-expression (5.1.2);

So why are lambdas expressions not allowed in an unevaluated operand but are allowed in the unevaluated portions of constant expressions?

I can see how for unevaluated operands the type information in several cases(decltype or typeid) is not very useful since each lambda has a unique type. Although why we would want to allow them in the unevaluated context of a constant expression is not clear, perhaps to allow for SFINAE?

解决方案

The core reason for the unevaluated operands exclusion is covered in C++ Standard Core Language Defect Reports and Accepted Issues #1607. Lambdas in template parameters which seeks to clarify this restriction and states the intention of the restriction in section 5.1.2 was to:

[...] avert the need to deal with them in function template signatures [...]

As the issue documents the current wording actually has a hole since costant expressions allows them in an unevaluated context. But it does not outright state the rationale for this restriction. The desire to avoid name mangling stands out and you can infer that avoiding extending SFINAE was also desired since the proposed resolution seeks to tighten the restriction even though several viable alternatives would have allowed SFINAE. The modified version of 5.1.2 paragraph 2 as follows:

A lambda-expression shall not appear in an unevaluated operand (Clause 5 [expr]), in a template-argument, in an alias-declaration, in a typedef declaration, or in the declaration of a function or function template outside its function body and default arguments [Note: The intention is to prevent lambdas from appearing in a signature —end note]. [Note: A closure object behaves like a function object (20.10 [function.objects]). —end note]

This proposal was accepted and is in N3936(see this answer for a link)

For a more explicit discussion of the rationale to avoid having lambdas as an unevaluated operand. The discussion titled Rationale for lambda-expressions not being allowed in unevaluated contexts on comp.lang.cpp.moderated Daniel Krügler lays out three reasons:

  1. The extreme extension of possible SFINAE cases :

    [...]The reason why they became excluded was due to exactly this extreme extension of sfinae cases (you were opening a Pandora box for the compiler)[...]

  2. In many cases it just useless since each lambda has a unique type, the hypothetical example given:

    template<typename T, typename U>
    void g(T, U, decltype([](T x, T y) { return x + y; }) func);
    
    g(1, 2, [](int x, int y) { return x + y; });
    

    The type of the lambda in the declaration and the call are different(by definition) and therefore this can not work.

  3. Name mangling also becomes a problem since once you allow a lambda in a function signature the bodies of the lambda will have to be mangled as well. This means coming up with rules to mangle every possible statement, which would burdensome for at least some implementations.

这篇关于为什么在未求值的操作数中不允许lambda表达式,但允许在常数表达式的未求值部分中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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