C++ 没有类似Java反射机制,无法动态获取对象元信息,那么如何检测对象是否存在成员函数呢?
?
1. 检测是否存在特定成员函数
muduo框架中有这样一段代码:
vi muduo/base/Singleton.h
class="cpp" name="code">template<typename T> struct has_no_destroy { template <typename C> static char test(decltype(&C::no_destroy)); // 返回char template <typename C> static int32_t test(...); // 返回int const static bool value = sizeof(test<T>(0)) == 1; }; static void init() { value_ = new T(); // 判断是否存在no_destroy方法 if (!detail::has_no_destroy<T>::value) { ::atexit(destroy); } }
?
?测试代码:
struct A
{
// empty
};
struct B
{
int no_destroy; // 成员变量
};
struct C
{
int no_destroy(){} // 成员函数
};
void test()
{
// 匹配test(&A::no_destroy) 时,由于A没有no_destroy方法,理论上应该报错。编译器寻找下一个匹配test(...),因此返回0
bool p1 = has_no_destroy<A>::value;
bool p2 = has_no_destroy<B>::value;
bool p3 = has_no_destroy<C>::value;
printf("%d %d %d\n", p1, p2, p3); // 输出 0 1 1
}
?
上文利用了c++ SFINAE(Substition Failure is not a error) 特性语法,即匹配失败不是错误。在进行模板特化,编译器会返回最佳匹配模板,避免失败。
?
2.?增强版本
上述代码,B的no_destroy成员也可以正常调用,那如何只检测成员函数呢?
成员函数要用对象来调用,可用declval构造对象。
struct check_no_destroy
{
/**
* 1. T 对象
* 2. U 获取T::no_destroy()返回值
* 3. 返回值类型为int
*/
template <typename T,
typename U = typename std::decay<decltype(std::declval<T>().no_destroy())>::type,
typename = typename std::enable_if<std::is_same<int, U>::value>::type>
static std::true_type Test(int);
template <typename>
static std::false_type Test(...);
};
template <typename T>
struct has_no_destroy :
public decltype(check_no_destroy::Test<T>(0))
{
};
void test()
{
/*
std::true_type = integral_constant<bool, true>;
显示值::value
*/
bool p = hash_no_destroy<D>::value;
cout << p << endl; // 1
}
?
3. std::declval
std::declval 返回对象的右值引用,不管对象是否有构造函数,一般配合decltype使用。
struct MyOb
{
MyObj1(){ cout << "Constuctor" << endl; }
int foo() const { return 1; }
};
struct MyObj
{
MyObj(const MyObj&){}
int foo() const { return 1; }
};
void test()
{
decltype(MyOb().foo()) n0 = 1; // ok, 构造函数不会调用
decltype(MyObj().foo()) n1 = 1; // 编译错误,MyObj没有默认构造函数
decltype(std::declval<MyObj>().foo()) n2 = 2; // ok, int
cout << typeid(n2).name() << endl; // i
}
?
?
?
?
?