This is different from checking if a specific function is defined. Here, for this check to return true
, the function has to be defined and passing the arguments
Making use of C++11, this can be done using a mixture of SFINAE, decltype
and std::declval
.
template
struct Bool
{ using type = bool; };
template
using BoolT = typename Bool::type;
template
struct DeclvalType
{
using type = typename std::conditional<
std::is_rvalue_reference::value,
T,
T &
>::type;
};
template
using DeclvalTypeT = typename DeclvalType::type;
template
struct ExtractFunction;
template
struct ExtractFunction
{ using type = T_Return(T_Args ...); };
template
struct ExtractFunction
{ using type = T_Return(T_Args ...); };
template
struct ExtractFunction
{ using type = T_Return(T_Args ...); };
template
struct ExtractFunction
{ using type = T_Return(T_Args ...); };
template
using ExtractFunctionT = typename ExtractFunction::type;
template
constexpr auto
impl(T_Function function) ->
BoolT>()
(std::declval>() ...)
)>
{ return true; }
template
constexpr bool
impl(...)
{ return false; }
template
constexpr bool
isFunctionCallable(T_Function function)
{ return impl(function); }
With the help of some more code (available in this Gist), it is possible to output tables showing what type of arguments can be passed to what type of parameters.
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 |
+--------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+
We can for example deduce from these tables that an argument of type T
can't be passed to a function that takes T &&
as parameter. Or that function(T &&)
only accepts arguments of type T &&
.
Note how deleting the copy and/or the move constructor reduce the possibilities since the arguments can't be converted implicitly anymore.
Edit:
Added support for member functions, thanks to @hvd.