C++ 【元编程】检查类型是否具有成员 hasattr

在python中,可以使用hasattr判断类型是否具有某个成员。

在C++中,有的时候我们要写一个模板函数,需要对模板进行一定的限制时。这些限制可能为“该模板函数仅用于拥有某个成员的类型”。在标准<type_traits>中,规定了一些列如is_copy_assignable等模板常量,用于判断是否拥有拷贝构造函数等成员,但对于其他自定义的成员,我们要如何判断呢?

在C++中有两种方式可以检查类型是否具有某个成员:

1、虚表运行期,通过多态和类似于COM组件地方式进行检查。这种方式可以在运行期间检查接口是否具有某个函数,通过SearchInterface这类型地函数进行接口查找,再通过AddRef等函数返回对应接口地指针。这种方式通过动态多态地方式判断某个已经存在地C++对象,是否具有某个接口函数地实现。但该种方式是通过从逻辑层面的判断,并通过dynamic_cast进行转换而进行hasattr的判断。但并不能直接判断某一个类是否具有某个成员函数。

2、元编程std:: SFINAE + void_t判断,在元编程中,类型分为有效类型和无效类型。void类型在普通的C++中是一个不完整类型,不能直接声明void对象,因为编译器不知道void类型的大小。但对于函数返回值来说,void是一个有效的类型。对于C++模板元编程来说,void是一个有效的类型。可以通过SFINAE+void_t来判断一个成员函数或者成员的类型是否有效,从而实现hasattr类似的效果。

SFINAE: Substitution Failure Is Not An Error 有兴趣的话可以上网查。大概意思就是,在编译期,模板匹配的时候,编译器会一直匹配,直到匹配到一个最合适的特化或者偏特化,如果中间出现匹配失败的话,也不会停。

以下我们用SFINAE+std::void_t 的方法来实现一个模板,用于判断类型是否具有my_test_func()成员,并支持const/non-const,左值/右值的判断。

template<typename T,typename = void>
constexpr bool has_my_test_func = false;

template<typename T>
constexpr bool has_my_test_func<T,std::void_t<decltype(
    std::declval<std::conditional_t<
        std::is_rvalue_reference_v<T>,
        std::remove_reference_t<T>&&,
        std::remove_reference_t<T>&>>().my_test_func()
    )>> = true;

上半部分为has_my_test_func的声明,下半部分为一个偏特化。当我们使用模板has_my_test_func<T>时,编译器会先去匹配下面的偏特化,如果能够成功通过void_t的有效类型检测,则应用到true值,若无法通过void_t的检测,则匹配到楼上的通用模板,值为false。

下面为测试代码:

class A{};
class B{private: void my_test_func();};
class C{public: void my_test_func();};
class D{public: int my_test_func();};
class E{public: void my_test_func()&;};
class F{public: void my_test_func()&&;};
class G{public: void my_test_func()const;};
class H{public: void my_test_func()const&&;};
    printf("%d\n",has_my_test_func<A>);         // 0
    printf("%d\n",has_my_test_func<B>);         // 0
    printf("%d\n",has_my_test_func<C>);         // 1
    printf("%d\n",has_my_test_func<D>);         // 1
    printf("%d\n",has_my_test_func<E>);         // 1
    printf("%d\n",has_my_test_func<E&&>);       // 0
    printf("%d\n",has_my_test_func<F>);         // 0
    printf("%d\n",has_my_test_func<F&&>);       // 1
    printf("%d\n",has_my_test_func<G>);         // 1
    printf("%d\n",has_my_test_func<const G>);   // 1
    printf("%d\n",has_my_test_func<H>);         // 0
    printf("%d\n",has_my_test_func<const H&>);  // 0
    printf("%d\n",has_my_test_func<const H&&>); // 1

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值