Skip to content

Instantly share code, notes, and snippets.

@ogrant
Created April 1, 2012 15:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ogrant/2276393 to your computer and use it in GitHub Desktop.
Save ogrant/2276393 to your computer and use it in GitHub Desktop.
C++11 Metaprogramming - Traits to check whether a function with a specific name can be called in the context defined by a signature
// Here is a traits structure I wrote to be able to determine if a function with
// a given name can be called in the context defined by a signature. This was
// originally not possible in C++03 - or at least a one solution works everywhere
// did not exist AFAIK.
//
// Olivier Grant
//
#include <iostream>
#include <iomanip>
#include <type_traits>
#define DECLARE_HAS_CALLABLE_TRAIT( name_, func_ ) \
\
namespace detail { \
\
template< typename ClassT, typename SignatureT > \
struct has_callable_helper_ ## name_; \
\
template< typename ClassT, typename RetT, typename ... ArgsVT > \
struct has_callable_helper_ ## name_ <ClassT,RetT ( ArgsVT ... )> \
{ \
private: \
template< typename T > \
struct check_return \
{ \
typedef std::integral_constant< \
bool, \
std::is_same<RetT,void>::value || \
std::is_convertible<T,RetT>::value \
> result; \
}; \
\
template< \
typename T, \
typename U = decltype(std::declval<T>().func_(std::declval<ArgsVT>()...)) \
> \
static \
typename check_return<U>::result test( void * ); \
\
template< typename T > \
static \
std::false_type test( ... ); \
\
typedef decltype(test<ClassT>(0)) result; \
\
public: \
static bool constexpr value = result::value; \
}; \
\
} \
\
template< typename ClassT, typename SignatureT > \
struct has_callable_ ## name_ \
: public std::integral_constant< \
bool, \
detail::has_callable_helper_ ## name_< \
ClassT, \
SignatureT \
>::value \
> \
{ };
///////////////////////////////////////////////////////////////////////////////////////
// Test related code.
///////////////////////////////////////////////////////////////////////////////////////
DECLARE_HAS_CALLABLE_TRAIT(func, func)
#define CHECK_VALUE( call_, expected_ ) \
{ \
auto const res(call_); \
\
std::cout \
<< (res == expected_ ? "Ok " : "Error") \
<< " - " \
<< #call_ \
<< " = " \
<< std::boolalpha << res \
<< "\n" \
; \
}
struct Test0
{
};
struct Test1
{
void func( )
{ std::cerr << "Test1::func\n"; }
};
struct Test2
{
int func( )
{ std::cerr << "Test2::func\n"; return 0; }
};
struct Test3
{
void func( double )
{ std::cerr << "Test3::func\n"; }
};
struct Test4
{
int func( double )
{ std::cerr << "Test4::func\n"; return 0; }
};
int main( )
{
CHECK_VALUE((has_callable_func<Test0,void ( )>::value), false)
CHECK_VALUE((has_callable_func<Test1,void ( )>::value), true)
CHECK_VALUE((has_callable_func<Test2,void ( )>::value), true)
CHECK_VALUE((has_callable_func<Test3,void ( )>::value), false)
CHECK_VALUE((has_callable_func<Test4,void ( )>::value), false)
CHECK_VALUE((has_callable_func<Test0,int ( )>::value), false)
CHECK_VALUE((has_callable_func<Test1,int ( )>::value), false)
CHECK_VALUE((has_callable_func<Test2,int ( )>::value), true)
CHECK_VALUE((has_callable_func<Test3,int ( )>::value), false)
CHECK_VALUE((has_callable_func<Test4,int ( )>::value), false)
CHECK_VALUE((has_callable_func<Test0,void ( double )>::value), false)
CHECK_VALUE((has_callable_func<Test1,void ( double )>::value), false)
CHECK_VALUE((has_callable_func<Test2,void ( double )>::value), false)
CHECK_VALUE((has_callable_func<Test3,void ( double )>::value), true)
CHECK_VALUE((has_callable_func<Test4,void ( double )>::value), true)
CHECK_VALUE((has_callable_func<Test0,int ( double )>::value), false)
CHECK_VALUE((has_callable_func<Test1,int ( double )>::value), false)
CHECK_VALUE((has_callable_func<Test2,int ( double )>::value), false)
CHECK_VALUE((has_callable_func<Test3,int ( double )>::value), false)
CHECK_VALUE((has_callable_func<Test4,int ( double )>::value), true)
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment