Home > database >  c 11 expanding parameter pack inside of a lambda
c 11 expanding parameter pack inside of a lambda

Time:09-21

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>();

CodePudding user response:

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)...);
    };
}

CodePudding user response:

You tagged C 11, so if the newest standard version you have in C 11, you'll need to do it recursively.

template <typename... Ts>
struct ExpandHelper;

template <>
struct ExpandHelper<> {
  void operator()() {
    // Empty body.
  }
}

template <typename T, typename... Ts>
struct ExpandHelper<T, Ts...> {
  void operator()() {
    Test<T>();
    ExpandHelper<Ts...> rest;
    rest();
  }
}

template <typename... Ts>
void expand() {
  std::function<void(void)> func = [] {
    ExpandHelper<Ts...> helper;
    helper();
  };
}

However, if you have access to C 17, you can use fold expressions with the comma operator, and the result is much shorter.

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