I'm storing an std::function inside a variadic class template (passed in the constructor of the class).
While doing so, I want to check that the types of the std::function parameters are the same as the types within the parameter pack of the class template. Here is an example:
template<typename... T>
class Foo {
public:
explicit Foo(std::function<void(T...)> f)
: func(std::move(f)) {
// static_assert(...) How to formulate the static_assert here?
}
std::function<void(T...)> func;
};
int main()
{
Foo<int> fooA([](int& a){}); // does not compile
Foo<int&> fooB([](int a){}); // should not compile, but does
Foo<int&> fooC([](int& a){}); // should compile
}
If a class Foo<int&> is defined with a reference type, I'd like to make sure that the lambda also takes an int by reference and not by value.
The other way around (Foo<int> and lambda with an int&) already does not compile as that lambda cannot be converted to a function taking an int by value.
Using a static_assert(), I tried to ensure that the type of the parameter in the lambda matches the type given as a template parameter to Foo.
So far, I have tried unwrapping the function arguments:
template<typename... T>
struct ID {};
template<typename Func>
struct Unwrap;
template<typename R, typename... Args>
struct Unwrap<R(Args...)> {
using ArgsType = ID<Args...>;
};
template<typename R, typename... Args>
struct Unwrap<std::function<R(Args...)>>
: Unwrap<R(Args...)> {};
...
static_assert(std::is_same<typename Unwrap<std::function<void(T...)>>::ArgsType, ID<T...>>::value, "");
...
Is there a way to achieve what I want? (Does it even make sense for me to think about such a check on my end, or should someone using my class Foo make sure, that he provides a lambda with the correct parameter types?)