消除函数指针和指向 class 实例的指针之间的歧义
disambiguate between function pointer and pointer to class instance
我有一个实用程序,它执行 static_assert
是否可以使用给定的参数列表调用函数。
我有 2 个重载:
对于 lambda 和自由函数:
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;
}
可以使用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");
}
我有一个实用程序,它执行 static_assert
是否可以使用给定的参数列表调用函数。
我有 2 个重载:
对于 lambda 和自由函数:
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;
}
可以使用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");
}