我有一个实用程序,它对是否可以使用给定的参数列表调用函数执行 static_assert
。
我有2次重载:
对于lambdas和自由函数:
template<typename Func, typename... Args>
void assert_is_callable(Func&&, Args&&...)
成员函数的:
template<typename Class, typename MemFunc, typename... Args>
void assert_is_callable(Class*, MemFunc, Args&&...)
我遇到的问题是,当我使用自由函数调用assert_is_callable
时,会选择第二个重载;函数指针推导为Class
,第一个参数推导为MemFunc
,其余参数Args...
void func(int, double, char) { }
assert_is_callable(func, 1, 2.3, 'c'); // selects the member_function version
编译错误输出:
In instantiation of 'void assert_is_callable(Class*, MemFunc, Args&& ...) [with Class = void(int, double, char); MemFunc = int; Args = {double, char}]':
prog.cpp:79:41: required from here
prog.cpp:51:5: error: static assertion failed: the provided type is not callable with the supplied arguments
static_assert(is_callable_member_function<Class, MemFunc, Args...>::value,
^
使用带有自由函数的assert_is_callable
时,如何防止选择成员函数重载?
#include <tuple>
#include <type_traits>
#include <functional>
// functor
template<class Func, class... Args>
class is_callable
{
using yes = char(&)[2];
using no = char(&)[1];
template<class F>
static yes check(decltype(std::declval<F&>()(std::declval<Args>()...))*);
template<class F>
static no check(...);
public:
enum { value = (sizeof(check<Func>(nullptr)) == sizeof(yes)) };
};
// member function
template<typename Class, typename MemFunc, class... Args>
class is_callable_member_function
{
using yes = char(&)[2];
using no = char(&)[1];
template<class C, class MF>
static yes check(decltype((std::declval<C>().*std::declval<MF>())(std::declval<Args>()...))*);
template<class C, class MF>
static no check(...);
public:
enum { value = (sizeof(check<Class, MemFunc>(nullptr)) == sizeof(yes)) };
};
//////////////////////////////////
template<typename Func, typename... Args>
void assert_is_callable(Func&&, Args&&...)
{
static_assert(is_callable<Func, Args...>::value,
"the provided type is not callable with the supplied arguments");
}
template<typename Class, typename MemFunc, typename... Args>
void assert_is_callable(Class*, MemFunc, Args&&...)
{
static_assert(is_callable_member_function<Class, MemFunc, Args...>::value,
"the provided type is not callable with the supplied arguments");
}
//////////////////////////////////
struct Foo
{
void func(int, double, char)
{
}
};
void func(int, double, char)
{
}
int main()
{
// member function
Foo f;
assert_is_callable(&f, &Foo::func, 1, 2.3, 'c');
// lambda
auto lambda = [](int, double, char) { };
assert_is_callable(lambda, 1, 2.3, 'c');
// free function
// assert_is_callable(func, 1, 2.3, 'c'); // selects the member_function version
return 0;
}
答案 0 :(得分:2)
您可以使用SFINAE,或直接使用强类型:
template<typename Class, typename C, typename MemFunc, typename... Args>
std::enable_if_t<std::is_class<Class>::value>
assert_is_callable(Class*, MemFunc (C::*), Args&&...)
{
static_assert(is_callable_member_function<Class, MemFunc (C::*), Args...>::value,
"the provided type is not callable with the supplied arguments");
}