C++学习---类型萃取---is_member_object_pointer/is_member_function_pointer

134 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情

背景

定义在<type_traits>中,用于判断一个类型是否是类的成员对象指针,是否是类的成员函数,属于基础的类型判断。

代码实现

gcc官网:gcc.gnu.org/

gcc代码下载:mirrors.tuna.tsinghua.edu.cn/help/gcc.gi…

gcc版本代码:gcc-7.5.0(branch分支)

文件位置:gcc/libstdc++-v3/include/std/type_traits

注意:以下的代码实现省略了一些宏定义部分,实际的代码还是参考gcc源码,这里仅用作相关原理分析。

实现分析

is_member_object_pointer

使用了一个__is_member_object_pointer_helper,其中的特化版本接受_Tp _Cp::*的类型,其中_Tp代表具体的类型,_Cp::*表示类的成员指针;注意到,这里继承了integral_constant,里面对_Tp进行了判断,因为一个类中除了成员变量就只有成员函数,判断不是函数,那就是变量了,这也是这个判断的原理。同样地,也需要使用remove_cv去除const和volatile属性。

  template<typename>
    struct __is_member_object_pointer_helper
    : public false_type { };

  template<typename _Tp, typename _Cp>
    struct __is_member_object_pointer_helper<_Tp _Cp::*>                                                                                                 
    : public integral_constant<bool, !is_function<_Tp>::value> { };

  /// is_member_object_pointer
  template<typename _Tp>
    struct is_member_object_pointer
    : public __is_member_object_pointer_helper<
                typename remove_cv<_Tp>::type>::type
    { };

is_member_function_pointer

同上面的判断,区别只是反向判断是函数。

  template<typename>
    struct __is_member_function_pointer_helper
    : public false_type { };

  template<typename _Tp, typename _Cp>
    struct __is_member_function_pointer_helper<_Tp _Cp::*>
    : public integral_constant<bool, is_function<_Tp>::value> { };

  /// is_member_function_pointer
  template<typename _Tp>
    struct is_member_function_pointer                                                                                                                    
    : public __is_member_function_pointer_helper<
                typename remove_cv<_Tp>::type>::type
    { };

类成员指针的使用

成员指针:数据类型 类名:: *指针名 = &类名::成员名

函数指针:函数返回类型名 (类名::*函数指针名)(参数列表) = &类名::成员函数名

由于类不是运行时 存在的对象。因此,在使用这类指针时,需要首先指定类的一个对象,然后,通过对象来引用指针所指向的成员/函数。

如下:

类对象名.*指向非静态数据成员的指针

类对象指针->*指向非静态数据成员的指针

(类对象名.*指向非静态成员函数的指针)(参数列表)

(类对象指针->*指向非静态成员函数的指针)(参数列表)

#include <iostream>

class A{
public:
    int a;
    int b;
    A(){}
    A(int a,int b):a(a),b(b){}
    void printAdd(){
        std::cout << "a+b=" << a+b << std::endl;
    }
};

int main(){
    // define member pointer
    int A::* pa = &A::a;
    int A::* pb = &A::b;
    void (A::* pPrintAdd)() = &A::printAdd;                                                                              
                                                                                                                                                         
    // define object and init pointer
    A test;
    test.*pa = 3;
    test.*pb = 4;
    (test.*pPrintAdd)();

    return 0;
}

使用案例

#include <iostream>
#include <type_traits>

class A{
public:
    int a;
    int func(){} 
};  
    
int main(){
    std::cout << std::boolalpha;
    std::cout << "------is_member_object_pointer------" << std::endl;
    std::cout << "int (A::*) :" << std::is_member_object_pointer<int (A::*)>::value << std::endl;
    std::cout << "A::a :" << std::is_member_object_pointer<decltype(&A::a)>::value << std::endl;
    std::cout << "int (A::*)() :" << std::is_member_object_pointer<int (A::*)()>::value << std::endl;
    
    std::cout << "------is_member_function_pointer------" << std::endl;
    std::cout << "int (A::*) :" << std::is_member_function_pointer<int (A::*)>::value << std::endl;                                                      
    std::cout << "A::func :" << std::is_member_function_pointer<decltype(&A::func)>::value << std::endl;
    std::cout << "int (A::*)() :" << std::is_member_function_pointer<int (A::*)()>::value << std::endl;
    return 0;
}

结果如下所示:分别识别出成员变量指针和成员函数指针。

总结

is_member_object_pointer/is_member_function_pointer分别识别成员变量指针,成员函数指针,成员指针实际上是不完整的指针,只记录了偏移地址,在具体使用时还需要配合实际的对象进行调用。