这与检查是否定义了特定功能不同。这里,要检查此返回true
,必须定义该函数,并且传递某种类型的参数应该会产生有效的调用。
示例:对于函数f
和类型为T &&
的参数,如果true
是直接或通过直接接受的有效函数,则检查应返回f
隐式转换 - 类型为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;
}
请注意this answer中解释的“参数”和“参数”之间的区别。
答案 0 :(得分:8)
利用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); }
借助更多代码(this Gist中提供),可以输出表格,显示哪些类型的参数可以传递给哪种类型的参数。
using T = Default (empty struct with implicit constructors):
+--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
| | |
| Function signature | Argument type |
| | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| | T | const T | volatile T | const volatile T | T & | const T & | volatile T & | const volatile T & | T && |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T) | x | x | | | x | x | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const T) | x | x | | | x | x | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(volatile T) | x | x | | | x | x | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const volatile T) | x | x | | | x | x | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T &) | x | | | | x | | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const T &) | x | x | | | x | x | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(volatile T &) | x | | x | | x | | x | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const volatile T &) | x | x | x | x | x | x | x | x | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T &&) | | | | | | | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
using T = NonCopiable:
+--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
| | |
| Function signature | Argument type |
| | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| | T | const T | volatile T | const volatile T | T & | const T & | volatile T & | const volatile T & | T && |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T) | | | | | | | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const T) | | | | | | | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(volatile T) | | | | | | | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const volatile T) | | | | | | | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T &) | x | | | | x | | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const T &) | x | x | | | x | x | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(volatile T &) | x | | x | | x | | x | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const volatile T &) | x | x | x | x | x | x | x | x | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T &&) | | | | | | | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
using T = NonMovable:
+--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
| | |
| Function signature | Argument type |
| | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| | T | const T | volatile T | const volatile T | T & | const T & | volatile T & | const volatile T & | T && |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T) | x | x | | | x | x | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const T) | x | x | | | x | x | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(volatile T) | x | x | | | x | x | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const volatile T) | x | x | | | x | x | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T &) | x | | | | x | | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const T &) | x | x | | | x | x | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(volatile T &) | x | | x | | x | | x | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const volatile T &) | x | x | x | x | x | x | x | x | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T &&) | | | | | | | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
using T = NonCopiableNonMovable:
+--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
| | |
| Function signature | Argument type |
| | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| | T | const T | volatile T | const volatile T | T & | const T & | volatile T & | const volatile T & | T && |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T) | | | | | | | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const T) | | | | | | | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(volatile T) | | | | | | | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const volatile T) | | | | | | | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T &) | x | | | | x | | | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const T &) | x | x | | | x | x | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(volatile T &) | x | | x | | x | | x | | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(const volatile T &) | x | x | x | x | x | x | x | x | |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
| function(T &&) | | | | | | | | | x |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
例如,我们可以从这些表中推断出T
类型的参数不能传递给以T &&
为参数的函数。或者function(T &&)
只接受T &&
类型的参数。
请注意删除副本和/或移动构造函数会减少可能性,因为参数不能再隐式转换。
修改强>
由于@hvd。
,添加了对会员功能的支持答案 1 :(得分:3)
#define overload_set(F)\
struct { auto operator()(auto&&...args)const\
->decltype(F(std::forward<decltype(args)>(args)...))\
{ return (F(std::forward<decltype(args)>(args)...)); }\
}
这会使用令牌F
并为F
生成重载集类型。
它并不完美:它只能通过SFINAE测试完美转发。但它很接近。
然后我们使用它:
template<class T,class=void>struct can_invoke:std::false_type{};
template<class F,class...Args>
struct can_invoke<F(Args...),
decltype(void(
std::declval<F>()(std::declval<Args>()...)
))
>:std::true_type{};
混合它们我们得到:
typedef overload_set(Foo) Foo_overloads;
std::cout << can_invoke<Foo_overloads(int, int) >::value<<"\n";
如果1
有效,将打印Foo(3,2)
。如上所述,这受到完美转发失败的限制。
您还可以将Foo_overloads{}
传递给期望函数对象的函数,并且它将在调用站点进行调度,而不是在传递函数对象时进行调度。