Search code examples
lambdascopec++14type-safetyenum-class

Why can a lambda expression return a local enum class type?


Why and how does this work? What type is 'auto' here?

auto lambda = [](){
    enum class Local { X=0 };
    return Local::X;
};

auto x = lambda(); // No error! Why and what type is auto in this case?
auto y = Local::X; // Error! Of course!

The enum class Local is not known outside the lambda a type. It's a enum class and therefore cannot be of type int without a cast, AFAIK. How can a local type be returned as auto and what type is it really outside the lambda?


Solution

  • Why and how does this work?

    It works because:

    • a lambda expression causes a unique class to be generated and named at compile time.
      • The type of this class is named by the compiler internally.
      • Hence the compiler may come up with something like <lambda_30560bd1c97ca682d011cd006c362574>::()::Local for x.

    You could obtain the lambda's type and then use that to declare objects of the type of the enum class contained within it:

    auto lambda = []() {
        enum class Local { X = 0, Z = 1 };
        return Local::X;
    };
    
    int main() {
        auto x = lambda(); // No error! Why and what type is auto in this case?
        //auto y = Local::X; // Error! Of course!
        using x_type = decltype(x);
        x_type y;
        y = x_type::Z; // can refer to enum members here
        y = x;
    }
    

    The enum class Local is not known outside the lambda a type.

    True, but the enum class is accessible if the relevant namespace is resolved. So internally <lambda_30560bd1c97ca682d011cd006c362574>::()::Local can resolve to Local inside the lambda, but it is not possible to guess this name before compilation, but we could use decltype or auto to get the type.

    It's a enum class and therefore cannot be of type int without a cast

    Correct. But it still exists in the same way that an enum class could exist inside of a regular class or struct.

    Without a known type, how can I continue work with that value outside the lambda?

    The utility of this type outside of the lambda is limited. It is not an int, but rather has its own unique type and so it would be of little value even though it can be indirectly obtained.