Undefined Behavior with the C++0x Closure: I

為{幸葍}努か 提交于 2019-12-01 20:09:19

(Edit: this certainly does not explain the ICE; I read the original question too hastily.)

The One problem in that code is that the lambdas returned from the adder function contain dangling references to the x variable that no longer exists. Capture by copy ([=] or [i]) instead of a reference ([&]) and everything should work.

It seems, that in your example trailing-return-type cannot be omitted. Here is excerpt from standard (5.1.2 Lambda expressions):

If a lambda-expression does not include a trailing-return-type, it is as if the trailing-return-type denotes the following type: — if the compound-statement is of the form { attribute-specifier-seq return expression ; } the type of the returned expression after lvalue-to-rvalue conversion (4.1), array-to-pointer conversion (4.2), and function-to-pointer conversion (4.3); — otherwise, void.

Returned value in your example cannot be used for conversions mentioned above. Following code with explicitely added return type compiles in VS 2010:

auto adder = [] (int x) -> std::function<int (int)> {
  return [=]( int y ) {
    return x + y;
  };
};

You're just completely missing the point. The need for std::function is very, very obvious.

  1. All lambdas have a unique type at compile-time
  2. You want the vector to hold any functional object at run-time.
  3. Therefore, some sort of type erasure is required, which is the job std::function does.

How on earth could you ever create a vector that varies at run-time a compile-time fact, like the type contained within it? That's just logically impossible- unless you use an abstraction such as std::function.

Of course, if you only ever want one lambda type within, then you don't need std::function at all. This is relatively rare though.

int main() {
    auto adder = [](int x) {
        return [=](int y) {
            return x + y;
        };
    };
    // alternatively- you MUST copy the argument as it will cease to exist
    // but once it's in the lambda, you can use "mutable" to allow you to
    // modify the copy that each lambda has.
    /*
    auto adder = [](int x) {
        return [=](int y) mutable {
            return x += y;
        };
    };
    */
    std::vector<decltype(adder(0))> adders;
    adders.emplace_back(adder(0));
    adders.emplace_back(adder(1));

    std::for_each(adders.begin(), adders.end(), [](decltype(*adders.begin())& ref) {
        std::cout << ref(33);
    });
    std::cin.get();
}

MSVC won't actually compile this little snippet, but I think that's a bug and judging by the reports of your compiler, I expect that it will compile there and indeed work correctly.

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