Last active
August 29, 2015 14:11
-
-
Save christophercrouzet/b3e4567c4fd3a9fe9b8c to your computer and use it in GitHub Desktop.
Check if a function that can be called with a specific set of arguments exists.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iomanip> | |
#include <iostream> | |
#include <string> | |
#include <type_traits> | |
#include <utility> | |
template<typename T> | |
struct Functions; | |
#define DEFINE_FUNCTIONS(PARAMETER) \ | |
template<> \ | |
struct Functions<PARAMETER> \ | |
{ \ | |
static void value(PARAMETER) {} \ | |
static void cValue(const PARAMETER) {} \ | |
static void vValue(volatile PARAMETER) {} \ | |
static void cvValue(const volatile PARAMETER) {} \ | |
static void reference(PARAMETER &) {} \ | |
static void cReference(const PARAMETER &) {} \ | |
static void vReference(volatile PARAMETER &) {} \ | |
static void cvReference(const volatile PARAMETER &) {} \ | |
static void rvalueReference(PARAMETER &&) {} \ | |
static void cRvalueReference(const PARAMETER &&) {} \ | |
static void vRvalueReference(volatile PARAMETER &&) {} \ | |
static void cvRvalueReference(const volatile PARAMETER &&) {} \ | |
}; | |
// ----------------------------------------------------------------------------- | |
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); } | |
// ----------------------------------------------------------------------------- | |
struct Default | |
{}; | |
struct NonCopiable | |
{ | |
NonCopiable(const NonCopiable &) = delete; | |
NonCopiable(NonCopiable &&) = default; | |
}; | |
struct NonMovable | |
{ | |
NonMovable(const NonMovable &) = default; | |
NonMovable(NonMovable &&) = delete; | |
}; | |
struct NonCopiableNonMovable | |
{ | |
NonCopiableNonMovable(const NonCopiableNonMovable &) = delete; | |
NonCopiableNonMovable(NonCopiableNonMovable &&) = delete; | |
}; | |
DEFINE_FUNCTIONS(Default); | |
DEFINE_FUNCTIONS(NonCopiable); | |
DEFINE_FUNCTIONS(NonMovable); | |
DEFINE_FUNCTIONS(NonCopiableNonMovable); | |
// ----------------------------------------------------------------------------- | |
template<typename T, typename T_Function> | |
void | |
printLine(T_Function function, const std::string &signature) | |
{ | |
using T1 = T; | |
using T2 = const T; | |
using T3 = volatile T; | |
using T4 = const volatile T; | |
using T5 = T &; | |
using T6 = const T &; | |
using T7 = volatile T &; | |
using T8 = const volatile T &; | |
using T9 = T &&; | |
using T10 = const T &&; | |
using T11 = volatile T &&; | |
using T12 = const volatile T &&; | |
std::cout << " " | |
<< "| " << signature << std::setw(31 - signature.size()) << " " | |
<< "| " << (isFunctionCallable<T1>(function) ? "x" : " ") << " " | |
<< "| " << (isFunctionCallable<T2>(function) ? "x" : " ") << " " | |
<< "| " << (isFunctionCallable<T3>(function) ? "x" : " ") << " " | |
<< "| " << (isFunctionCallable<T4>(function) ? "x" : " ") << " " | |
<< "| " << (isFunctionCallable<T5>(function) ? "x" : " ") << " " | |
<< "| " << (isFunctionCallable<T6>(function) ? "x" : " ") << " " | |
<< "| " << (isFunctionCallable<T7>(function) ? "x" : " ") << " " | |
<< "| " << (isFunctionCallable<T8>(function) ? "x" : " ") << " " | |
<< "| " << (isFunctionCallable<T9>(function) ? "x" : " ") << " " | |
<< "| " << (isFunctionCallable<T10>(function) ? "x" : " ") << " " | |
<< "| " << (isFunctionCallable<T11>(function) ? "x" : " ") << " " | |
<< "| " << (isFunctionCallable<T12>(function) ? "x" : " ") << " " | |
<< "|" | |
<< std::endl; | |
std::cout << " +---------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+---------------+-----------------+-----------------------+" << std::endl; | |
} | |
template<typename T> | |
void | |
printTable() | |
{ | |
std::cout << " +---------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+" << std::endl; | |
std::cout << " | | |" << std::endl; | |
std::cout << " | Function signature | Argument type |" << std::endl; | |
std::cout << " | | |" << std::endl; | |
std::cout << " +---------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+---------------+-----------------+-----------------------+" << std::endl; | |
std::cout << " | | T | const T | volatile T | const volatile T | T & | const T & | volatile T & | const volatile T & | T && | const T && | volatile T && | const volatile T && |" << std::endl; | |
std::cout << " +---------------------------------+-----+-----------+---------------+---------------------+-------+-------------+-----------------+-----------------------+---------+---------------+-----------------+-----------------------+" << std::endl; | |
printLine<T>(Functions<T>::value, "function(T)"); | |
printLine<T>(Functions<T>::cValue, "function(const T)"); | |
printLine<T>(Functions<T>::vValue, "function(volatile T)"); | |
printLine<T>(Functions<T>::cvValue, "function(const volatile T)"); | |
printLine<T>(Functions<T>::reference, "function(T &)"); | |
printLine<T>(Functions<T>::cReference, "function(const T &)"); | |
printLine<T>(Functions<T>::vReference, "function(volatile T &)"); | |
printLine<T>(Functions<T>::cvReference, "function(const volatile T &)"); | |
printLine<T>(Functions<T>::rvalueReference, "function(T &&)"); | |
printLine<T>(Functions<T>::cRvalueReference, "function(const T &&)"); | |
printLine<T>(Functions<T>::vRvalueReference, "function(volatile T &&)"); | |
printLine<T>(Functions<T>::cvRvalueReference, "function(const volatile T &&)"); | |
} | |
// ----------------------------------------------------------------------------- | |
int | |
main(int argc, char **av) | |
{ | |
std::cout << std::endl; | |
std::cout << "using T = Default (empty struct with implicit constructors):" << std::endl << std::endl; | |
printTable<Default>(); | |
std::cout << std::endl; | |
std::cout << std::endl; | |
std::cout << "using T = NonCopiable:" << std::endl << std::endl; | |
printTable<NonCopiable>(); | |
std::cout << std::endl; | |
std::cout << std::endl; | |
std::cout << "using T = NonMovable:" << std::endl << std::endl; | |
printTable<NonMovable>(); | |
std::cout << std::endl; | |
std::cout << std::endl; | |
std::cout << "using T = NonCopiableNonMovable:" << std::endl << std::endl; | |
printTable<NonCopiableNonMovable>(); | |
std::cout << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment