c++类型萃取

2022/7/26 14:25:03

本文主要是介绍c++类型萃取,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

判断两个类型的关系

#include <iostream>
#include <type_traits>

using std::cout;
using std::endl;

// is_same is used to judge two data types same or not during compiling
void test_is_same()
{
    cout << "test is_same:" << endl;
    cout << std::is_same<int, int>::value << endl;
    cout << std::is_same<int, unsigned int>::value << endl;
    cout << std::is_same<int, signed int>::value << endl;
}

// is_base_of is used to judge the relationship between two data types is inheritance
namespace test_is_base_of
{
    class A
    {
    };
    class B : A
    {
    };
    class C
    {
    };

    void test_is_base_of()
    {
        cout << "test is_base_of:" << endl;
        cout << std::is_base_of<A, B>::value << endl;
        cout << std::is_base_of<B, A>::value << endl;
        cout << std::is_base_of<C, B>::value << endl;
    }
};

// is_convertible is used to judge if the first parameter data type could be converted to the second parameter data type
namespace test_is_convertible
{
    class A
    {
    };
    class B : public A
    {
    };
    class C
    {
    };
    void test_is_convertible()
    {
        cout << "test is_convertible:" << endl;
        bool b2a = std::is_convertible<B *, A *>::value;
        bool a2b = std::is_convertible<A *, B *>::value;
        bool b2c = std::is_convertible<B *, C *>::value;

        cout << std::boolalpha;
        cout << b2a << endl;
        cout << a2b << endl;
        cout << b2c << endl;
    }
};

int main(void)
{
    test_is_same();
    test_is_base_of::test_is_base_of();
    test_is_convertible::test_is_convertible();
    return 0;
}

 

类型转换

#include <iostream>
#include <type_traits>

using std::cout;
using std::endl;

/*
常用的类型转换traits
const的添加与移除
引用的添加与移除
数组的修改和指针的修改
*/
void base_using()
{
    cout << std::boolalpha;
    // 添加const
    cout << std::is_same<const int, std::add_const<int>::type>::value << endl;
    // 移除const
    cout << std::is_same<int, std::remove_const<const int>::type>::value << endl;
    // 添加左值引用
    cout << std::is_same<int &, std::add_lvalue_reference<int>::type>::value << endl;
    // 添加右值引用
    cout << std::is_same<int &&, std::add_rvalue_reference<int>::type>::value << endl;
    // 移除左值引用
    cout << std::is_same<int, std::remove_reference<int &>::type>::value << endl;
    // 移除右值引用
    cout << std::is_same<int, std::remove_reference<int &&>::type>::value << endl;
    // 添加指针
    cout << std::is_same<int *, std::add_pointer<int>::type>::value << endl;
    // 移除数组顶层维度
    cout << std::is_same<int, std::remove_extent<int[]>::type>::value << endl;
    cout << std::is_same<int[2], std::remove_extent<int[][2]>::type>::value << endl;
    cout << std::is_same<int[2][3], std::remove_extent<int[][2][3]>::type>::value << endl;
    cout << std::is_same<int[2][3], std::remove_extent<int[4][2][3]>::type>::value << endl;
    // 移除数组所有维度
    cout << std::is_same<int, std::remove_all_extents<int[][2][3]>::type>::value << endl;
    // 取公共类型
    typedef std::common_type<unsigned char, short, int>::type NumericType;
    cout << std::is_same<int, NumericType>::value << endl;
}


int main(void)
{
    base_using();
    return 0;
}

 

注意,根据模板参数类创建对象时,要注意移除引用

创建对象是需要使用原始类型,不能使用引用类型,而模板参数T可能是引用类型,所以需要提前移除可能存在的引用

// attention! 根据模板参数类创建对象时,要注意移除引用
template <typename T>
typename std::remove_reference<T>::type *Create()
{
    typedef typename std::remove_reference<T>::type U;
    return new U();
}

 

添加和移除引用实例

#include <iostream>
#include <type_traits>
#include <memory>

using std::cout;
using std::endl;

// 有时需要添加引用类型,比如从智能指针中获取对象的引用时
template <class T>
struct Construct
{
    // step1: 去掉引用,将去掉引用的数据类型定义为U
    typedef typename std::remove_reference<T>::type U;
    // step3: 创建构造函数
    Construct() : m_ptr(new U)
    {
    }
    // step4: 获取成员变量值,加上引用和const
    typename std::add_lvalue_reference<U>::type Get() const
    {
        return *m_ptr.get();
    }

private:
    // step2: 用定义的数据类型U
    std::unique_ptr<U> m_ptr;
};

int main()
{
    Construct<int> c;
    int a = c.Get();
    cout << a << endl;
    return 0;
}

 

decay

对于有cv(const/volatile)操作符修饰的变量很难直接取到他的原始类型,所以西药先移除引用,再移除cv运算符,方法如下

template <typename T>
typename std::remove_cv<typename std::remove_reference<T>::type>::type *Create()
{
    typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type U;
    return new U();
}

但是这么写实在是太长了,所以有了decay,decay不光可以处理普通变量,还可以处理函数和数组,他的处理逻辑如下

1.移除引用

2.判断是不是数组,如果是数组,把数组编程数组指针,结束

3.否则 判断是不是函数,如果是函数,把函数变成函数指针,结束

4.如果都不是,移除cv符(普通变量)

void test_decay()
{
    cout << std::boolalpha;
    cout << std::is_same<int, std::decay<int>::type>::value << endl;
    cout << std::is_same<int, std::decay<int &>::type>::value << endl;
    cout << std::is_same<int, std::decay<int &&>::type>::value << endl;
    cout << std::is_same<int, std::decay<const int &>::type>::value << endl;
    cout << std::is_same<int *, std::decay<int[2]>::type>::value << endl;
    cout << std::is_same<int (*)(int), std::decay<int(int)>::type>::value << endl;
}

std::decay对于函数来说是添加指针,利用这一点可以将函数变成函数指针,从而将函数指针变量保存起来,在后面延迟执行

template <typename F>
struct SimpFunction
{
    using FnType = typename std::decay<F>::type;
    SimpFunction(F &f) : m_fn(f) {}
    void Run()
    {
        m_fn();
    }
    FnType m_fn;
};

 

编译期选择std::conditional<bool B,class T, class F>

在std::conditional的模板参数中,B如果为true,则conditional::type为T, 否则为F

#include <iostream>
#include <type_traits>

using std::cout;
using std::endl;

void test_conditional()
{
    using A = std::conditional<true, int, float>::type;
    using B = std::conditional<false, int, float>::type;
    cout << std::boolalpha;
    cout << std::is_same<int, A>::value << endl;
    cout << std::is_same<float, B>::value << endl;
    cout << std::is_same<long, std::conditional<std::is_integral<A>::value, long, int>::type>::value << endl;
    cout << std::is_same<int, std::conditional<std::is_integral<B>::value, long, int>::type>::value << endl;

    // 比较两个类型,输出较大的类型
    using max_size_t = std::conditional<(sizeof(long long) > sizeof(long double)), long long, long double>::type;
    cout << typeid(max_size_t).name() << endl;
}

int main(void)
{
    test_conditional();
    return 0;
}

可以通过编译期的判断式来选择类型,这给我们动态选择类型提供了很大的灵活性

 



这篇关于c++类型萃取的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程