Используя 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 &&
.
Обратите внимание, что удаление копии и/или конструктора перемещения уменьшает возможности, поскольку аргументы не могут быть преобразованы неявно.
Edit:
Добавлена поддержка для функций-членов, благодаря @hvd.
Просто предупреждение: это невозможно сделать, если ваша функция перегружена. – hvd
Правда, спасибо, что указали это! Вот почему в коде Gist мне пришлось обернуть функции внутри структуры. Кроме того, он не будет работать и с функциями-членами. Я не могу придумать, как исправить эти два недостатка, хотя идея? – ChristopherC
Вы можете иметь дело с функциями-членами, превратив их в обычные функции: использовать черту типа, которая извлекает 'Ret (Args ...)' из 'Ret (T :: *) (Args ...)', а затем вы можете используйте то, что у вас уже есть. Но я не думаю, что есть способ получить что-то, что работает для перегруженных функций. – hvd