So I fiddled around with some of the type_traits stuff, and I think I have something that verifies the entire signature, not just the return value, and allows you to create easy to read static_asserts rather than illegible template errors when the signature doesn't match. Is this a bad solution?
#include <functional>
template<typename, typename, typename = void>
struct is_signature : std::false_type {};
template<typename TFunc, typename Ret, typename... Args>
struct is_signature<TFunc, Ret(Args...),
typename std::enable_if<
std::is_convertible<
TFunc,
std::function<Ret(Args...)>
>::value
>::type
> : public std::true_type
{};
// works on both functions and lambda's
void blah(int, int) {
}
template<typename TFunc>
void templFunc(TFunc func) {
static_assert(is_signature<TFunc, void(int, int)>::value, "Not gonna work! more info follows:");
func(3, 6);
}
int main() {
auto b = [](int, int) -> void {
};
auto c = [](int) -> void {
};
static_assert(is_signature<decltype(b), void(int, int)>::value, "b convertible to a std::function<void(int, int), so this checks out!");
static_assert(is_signature<decltype(b), void(int)>::value, "b not convertible to a std::function<void(int)>, so this will error in compilation.");
static_assert(is_signature<decltype(blah), void(int, int)>::value, "blah convertible to a std::function<void(int, int), so this checks out!");
static_assert(is_signature<decltype(blah), void(int)>::value, "blah not convertible to a std::function<void(int)>, so this will error in compilation.");
templFunc(b); // <- ok
templFunc(c); // <- static assertion : not gonna work!
return 0;
}