Search code examples
c++c++11parameter-pack

c++11 expanding parameter pack inside of a lambda


I'm trying to assign a lambda to my std::function that contains 1 call to Test for each type specified in the parameter pack, does anyone know how to do this?

template<typename T>
void Test() {
    
}

template<typename ... Ts>
void Expand() {
    std::function<void(void)> func = [Ts] {
        for (const auto& p : { Ts... })
        Test<Ts...>();
    };
}

int main(int argc, char** argv) {
    Expand<int, char>();
}

I am trying to have this expand to...

Test<int>();
Test<char>();

Solution

  • template<typename ... Ts>
    

    Ts here represents types. Template parameters are types.

    [Ts] {
    // ...
    }
    

    A lambda's capture captures values, and discrete objects rather than types. There's no such thing as a capture of types.

    for (const auto& p : { Ts... })
    

    Range iteration iterates over values in some container. A braced initialization list is a list values too, not types.

    The major confusion here is the confusion between types and values, in C++.

    If the intent is to generate "call to Test for each type specified in the parameter pack", then the simplest solution is to use C++17's fold expression:

    template<typename ... Ts>
    void Expand() {
        std::function<void(void)> func = [] {
            ( Test<Ts>(), ...);
        };
    }
    

    You tagged your question as C++11, but in the year 2022 it is highly likely that your compiler support C++17 as well.

    In the unlikely event that you're limited to C++11, a helper throwaway void function can be used as a crutch:

    template<typename ...Args>
    void ignore_me(Args && ...args)
    {
    }
    
    template<typename ... Ts>
    void Expand() {
        std::function<void(void)> func = [] {
            ignore_me( (Test<Ts>, 0)...);
        };
    }