下面是我的版本,它可以任意处理所有可能的成员函数重载,包括模板成员函数,可能带有默认实参。当成员函数调用某个类类型时,它区分了3种互斥的情况,给定的arg类型:(1)有效,或(2)模糊,或(3)不可用。使用示例:
#include <string>
#include <vector>
HAS_MEM(bar)
HAS_MEM_FUN_CALL(bar)
struct test
{
void bar(int);
void bar(double);
void bar(int,double);
template < typename T >
typename std::enable_if< not std::is_integral<T>::value >::type
bar(const T&, int=0){}
template < typename T >
typename std::enable_if< std::is_integral<T>::value >::type
bar(const std::vector<T>&, T*){}
template < typename T >
int bar(const std::string&, int){}
};
现在你可以这样使用它:
int main(int argc, const char * argv[])
{
static_assert( has_mem_bar<test>::value , "");
static_assert( has_valid_mem_fun_call_bar<test(char const*,long)>::value , "");
static_assert( has_valid_mem_fun_call_bar<test(std::string&,long)>::value , "");
static_assert( has_valid_mem_fun_call_bar<test(std::vector<int>, int*)>::value , "");
static_assert( has_no_viable_mem_fun_call_bar<test(std::vector<double>, double*)>::value , "");
static_assert( has_valid_mem_fun_call_bar<test(int)>::value , "");
static_assert( std::is_same<void,result_of_mem_fun_call_bar<test(int)>::type>::value , "");
static_assert( has_valid_mem_fun_call_bar<test(int,double)>::value , "");
static_assert( not has_valid_mem_fun_call_bar<test(int,double,int)>::value , "");
static_assert( not has_ambiguous_mem_fun_call_bar<test(double)>::value , "");
static_assert( has_ambiguous_mem_fun_call_bar<test(unsigned)>::value , "");
static_assert( has_viable_mem_fun_call_bar<test(unsigned)>::value , "");
static_assert( has_viable_mem_fun_call_bar<test(int)>::value , "");
static_assert( has_no_viable_mem_fun_call_bar<test(void)>::value , "");
return 0;
}
下面是用c++11编写的代码,但是,你可以很容易地将它移植到具有typeof扩展的非c++11(例如gcc)。你可以用你自己的宏替换HAS_MEM宏。
#pragma once
#if __cplusplus >= 201103
#include <utility>
#include <type_traits>
#define HAS_MEM(mem) \
\
template < typename T > \
struct has_mem_##mem \
{ \
struct yes {}; \
struct no {}; \
\
struct ambiguate_seed { char mem; }; \
template < typename U > struct ambiguate : U, ambiguate_seed {}; \
\
template < typename U, typename = decltype(&U::mem) > static constexpr no test(int); \
template < typename > static constexpr yes test(...); \
\
static bool constexpr value = std::is_same<decltype(test< ambiguate<T> >(0)),yes>::value ; \
typedef std::integral_constant<bool,value> type; \
};
#define HAS_MEM_FUN_CALL(memfun) \
\
template < typename Signature > \
struct has_valid_mem_fun_call_##memfun; \
\
template < typename T, typename... Args > \
struct has_valid_mem_fun_call_##memfun< T(Args...) > \
{ \
struct yes {}; \
struct no {}; \
\
template < typename U, bool = has_mem_##memfun<U>::value > \
struct impl \
{ \
template < typename V, typename = decltype(std::declval<V>().memfun(std::declval<Args>()...)) > \
struct test_result { using type = yes; }; \
\
template < typename V > static constexpr typename test_result<V>::type test(int); \
template < typename > static constexpr no test(...); \
\
static constexpr bool value = std::is_same<decltype(test<U>(0)),yes>::value; \
using type = std::integral_constant<bool, value>; \
}; \
\
template < typename U > \
struct impl<U,false> : std::false_type {}; \
\
static constexpr bool value = impl<T>::value; \
using type = std::integral_constant<bool, value>; \
}; \
\
template < typename Signature > \
struct has_ambiguous_mem_fun_call_##memfun; \
\
template < typename T, typename... Args > \
struct has_ambiguous_mem_fun_call_##memfun< T(Args...) > \
{ \
struct ambiguate_seed { void memfun(...); }; \
\
template < class U, bool = has_mem_##memfun<U>::value > \
struct ambiguate : U, ambiguate_seed \
{ \
using ambiguate_seed::memfun; \
using U::memfun; \
}; \
\
template < class U > \
struct ambiguate<U,false> : ambiguate_seed {}; \
\
static constexpr bool value = not has_valid_mem_fun_call_##memfun< ambiguate<T>(Args...) >::value; \
using type = std::integral_constant<bool, value>; \
}; \
\
template < typename Signature > \
struct has_viable_mem_fun_call_##memfun; \
\
template < typename T, typename... Args > \
struct has_viable_mem_fun_call_##memfun< T(Args...) > \
{ \
static constexpr bool value = has_valid_mem_fun_call_##memfun<T(Args...)>::value \
or has_ambiguous_mem_fun_call_##memfun<T(Args...)>::value; \
using type = std::integral_constant<bool, value>; \
}; \
\
template < typename Signature > \
struct has_no_viable_mem_fun_call_##memfun; \
\
template < typename T, typename... Args > \
struct has_no_viable_mem_fun_call_##memfun < T(Args...) > \
{ \
static constexpr bool value = not has_viable_mem_fun_call_##memfun<T(Args...)>::value; \
using type = std::integral_constant<bool, value>; \
}; \
\
template < typename Signature > \
struct result_of_mem_fun_call_##memfun; \
\
template < typename T, typename... Args > \
struct result_of_mem_fun_call_##memfun< T(Args...) > \
{ \
using type = decltype(std::declval<T>().memfun(std::declval<Args>()...)); \
};
#endif