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 }
?
?
?
?
?