Skip to content

Instantly share code, notes, and snippets.

@christophercrouzet
Last active August 29, 2015 14:11
Show Gist options
  • Save christophercrouzet/b3e4567c4fd3a9fe9b8c to your computer and use it in GitHub Desktop.
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.
#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