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