C++ 如何在编译时检查是否存在可以使用一组特定参数调用的函数?
这与检查是否定义了特定函数不同。在这里,要使此检查返回C++ 如何在编译时检查是否存在可以使用一组特定参数调用的函数?,c++,function,templates,compile-time,C++,Function,Templates,Compile Time,这与检查是否定义了特定函数不同。在这里,要使此检查返回true,必须定义函数,并且传递特定类型的参数应导致有效调用 示例:对于函数f和类型为T&的参数,如果f是直接或通过隐式转换接受类型为T&的参数的有效函数,则检查应返回true void f(int &) {}; int main(int argc, char **av) { isFunctionCallable<int>(f); // true because `int i; f(i);` is valid.
true
,必须定义函数,并且传递特定类型的参数应导致有效调用
示例:对于函数f
和类型为T&
的参数,如果f
是直接或通过隐式转换接受类型为T&
的参数的有效函数,则检查应返回true
void f(int &) {};
int main(int argc, char **av)
{
isFunctionCallable<int>(f); // true because `int i; f(i);` is valid.
isFunctionCallable<int &&>(f); // false because `int i; f(std::move(i));` is invalid.
return 0;
}
void f(int&){};
内部主(内部argc,字符**av)
{
isFunctionCallable(f);//为true,因为'int i;f(i);'有效。
isFunctionCallable(f);//false,因为`int i;f(std::move(i));`无效。
返回0;
}
请注意中解释的“参数”和“参数”之间的区别。使用C++11,这可以使用SFINAE、
decltype
和std::declval
的混合来完成
template<typename ...>
struct Bool
{ using type = bool; };
template<typename ... T_Dummies>
using BoolT = typename Bool<T_Dummies ...>::type;
template<typename T>
struct DeclvalType
{
using type = typename std::conditional<
std::is_rvalue_reference<T>::value,
T,
T &
>::type;
};
template<typename T>
using DeclvalTypeT = typename DeclvalType<T>::type;
template<typename T>
struct ExtractFunction;
template<typename T_Return, typename ... T_Args>
struct ExtractFunction<T_Return(T_Args ...)>
{ using type = T_Return(T_Args ...); };
template<typename T_Return, typename ... T_Args>
struct ExtractFunction<T_Return(*)(T_Args ...)>
{ using type = T_Return(T_Args ...); };
template<typename T, typename T_Return, typename ... T_Args>
struct ExtractFunction<T_Return(T::*)(T_Args ...)>
{ using type = T_Return(T_Args ...); };
template<typename T, typename T_Return, typename ... T_Args>
struct ExtractFunction<T_Return(T::*)(T_Args ...) const>
{ using type = T_Return(T_Args ...); };
template<typename T>
using ExtractFunctionT = typename ExtractFunction<T>::type;
template<typename ... T, typename T_Function>
constexpr auto
impl(T_Function function) ->
BoolT<decltype(
std::declval<ExtractFunctionT<T_Function>>()
(std::declval<DeclvalTypeT<T>>() ...)
)>
{ return true; }
template<typename ... T>
constexpr bool
impl(...)
{ return false; }
template<typename ... T, typename T_Function>
constexpr bool
isFunctionCallable(T_Function function)
{ return impl<T ...>(function); }
例如,我们可以从这些表中推断,T
类型的参数不能传递给以T&
为参数的函数。或者函数(T&&
只接受T&
类型的参数
void f(int &) {};
int main(int argc, char **av)
{
isFunctionCallable<int>(f); // true because `int i; f(i);` is valid.
isFunctionCallable<int &&>(f); // false because `int i; f(std::move(i));` is invalid.
return 0;
}
请注意,删除副本和/或移动构造函数如何减少可能发生的情况,因为参数不能再进行隐式转换
编辑:
由于@hvd,增加了对成员函数的支持
#define overload_set(F)\
struct { auto operator()(auto&&...args)const\
->decltype(F(std::forward<decltype(args)>(args)...))\
{ return (F(std::forward<decltype(args)>(args)...)); }\
}
将它们混合在一起,我们得到:
typedef overload_set(Foo) Foo_overloads;
std::cout << can_invoke<Foo_overloads(int, int) >::value<<"\n";
typedef重载集(Foo)Foo重载;
std::这仅仅是一个警告:如果您的函数过载,这将无法工作。是的,谢谢您指出这一点!这也是为什么在Gist代码中我必须将函数包装在结构中的原因。除此之外,它对成员函数也不起作用。但是,我想不出一种方法来修复这两个缺陷,你可以通过将成员函数转换成常规函数来处理它们:使用一个类型特征,从Ret(t::*)(Args…
)中提取Ret(Args…
,然后你可以使用你已经拥有的。但是我不认为有任何方法可以让重载函数工作。我认为我有一个类型特征,可以像你建议的那样工作(),但我不知道如何在代码中集成它,一次给我带来太多新概念isFunctionCallable(f)
将T_函数
推断为void(*)(int&)
,而不是void(int&)
,并且ExtractFunction
的实现还没有处理函数指针。为此添加一个专门化,我得到1
作为输出。
typedef overload_set(Foo) Foo_overloads;
std::cout << can_invoke<Foo_overloads(int, int) >::value<<"\n";