lambda capture during initialization should be an error

寵の児 提交于 2019-12-04 04:17:24

问题


What I'm trying to do is eat exceptions when constructing an object that may be invalid. It'd be perfect for use of std::optional, but I don't believe the omission of std::optional changes the error I see: the object is being captured and used before it's been initialized. I don't believe it should be captured in the first place because we haven't reached a sequence point to the best of my knowledge (does a lambda initialization count as a sequence point?). Moreover, the bug is IMO easily catchable human error (and even does get caught... depending upon circumstances).

How (more importantly, why) is the lambda able to capture and use the not-yet-initialized foo?

https://godbolt.org/g/IwcHrV

#include <string>
using namespace std;

void foo() {
  string foo = [&]()->string{
    // using foo before it's been initialized == undefined behavior
    auto guessed_foo = to_string(1234);
    if ( begin(foo) == end(foo) ) {
      return guessed_foo;
    }
    return {};
  }();
}

Compiler exited with result code 0

But... replacing the declaration of string foo with auto foo does appear to cause an error similar to what I'd like to see.

https://godbolt.org/g/GfE4WH

#include <string>
using namespace std;

void foo() {
  auto foo = [&]()->string{
    auto guessed_foo = to_string(1234);
    if ( begin(foo) == end(foo) ) {
      return guessed_foo;
    }
    return {};
  }();
}

error: variable 'foo' declared with 'auto' type cannot appear in its own initializer

Note that I found this using GCC 6.2 on Ubuntu 16.04 LTS. The configuration in Godbolt is using clang 3.9.1. Both are configured for c++14.

So my questions are:

  • Why is the lambda capture for an initialization of a non-auto-declared variable able to capture and use the (not-yet-initialized) variable?
  • Why does auto get (in my opinion, correctly) caught and errored?
  • Moreover, why the difference between the above two? It sounds like compiler bugs, but... is there something specific in the standard declaring this to be correct behavior?
  • This could be taken as an argument for auto keyword?

回答1:


The second snippet runs into [dcl.spec.auto]/10:

If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression, the program is ill-formed.

The type of foo is needed to determine the type of the expression foo within the lambda body, but at that point you haven't deduced foo's type yet, so the program is ill-formed.


As to why you are allowed to capture something before its initialization, see generally Why is 'int i = i;' legal?. We have many examples of recursive lambdas using std::function:

std::function<void(int)> foo = [&foo](int i){ return foo(i - 1); };


来源:https://stackoverflow.com/questions/43052499/lambda-capture-during-initialization-should-be-an-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!