相关系列文章
目录
1.案例
现在有这样一个函数:
- template <typename Container>
- void func(Container t, const char* pMessage){ }
需要从容器 t 中获取元素的类型,首先我们想到的是:
- #include
- #include
-
- template <typename Container>
- void func(Container& t, const char* pMessage)
- {
- using TYPE = decltype(*t.begin());
- std::cout << pMessage << boost::typeindex::type_id_with_cvr<decltype(TYPE)>().pretty_name() << std::endl;
- }
函数调用:
- std::vector<int> array4;
- func(array4, "array4 value type is: "); //编译正确
-
- int array1[5] = {0, 1,3,4,8};
- func(array1, "array1 value type is: "); //编译报错
屏蔽编译错误,输出:
array4 value type is: int&
如果需要定义跟t中元素一样类型的变量, 如:
TYPE temp;
编译报错, 那是因为TYPE是int&,如果需要定义,就必须去掉引用,于是想到了std::decay, 它的作用是取出基本类型, 为类型T应用从左值到右值(lvalue-to-rvalue)、数组到指针(array-to-pointer)和函数到指针(function-to-pointer)的隐式转换。转换将移除类型T的cv限定符(const和volatile限定符),上面的代码就可以这样写:
- #include
- #include
-
- template <typename Container>
- void func(Container& t, const char* pMessage)
- {
- using TYPE = std::decay<decltype(*t.begin())>;
- std::cout << pMessage << boost::typeindex::type_id_with_cvr<decltype(TYPE)>().pretty_name() << std::endl;
- }
函数调用:
- std::vector<int> array4;
- func(array4, "array4 value type is: "); //编译正确
-
- int array1[5] = {0, 1,3,4,8};
- func(array1, "array1 value type is: "); //编译还是报错
屏蔽编译错误,输出:
array4 value type is: int
此时函数调用func(array1, "array1 value type is: ")还是报错,主要是func没有考虑容器是数组的情况,利用C++11之后系统提供的std::begin()就可以满足要求,于是代码修改如下:
- #include
- #include
-
- template <typename Container>
- void func(Container& t, const char* pMessage)
- {
- using TYPE = std::decay<decltype(*std::begin(t)>;
- std::cout << pMessage << boost::typeindex::type_id_with_cvr<decltype(TYPE)>().pretty_name() << std::endl;
- }
函数调用:
- std::vector<int> array4;
- func(array4, "array4 value type is: "); //编译正确
-
- int array1[5] = {0, 1,3,4,8};
- func(array1, "array1 value type is: "); //编译正确
输出:
- array4 value type is: int
- array1 value type is: int
2.解决方法
上面的代码都是基于C++标准容器的,从std::begin()可以联想到STL中标准容器中有个value_type,可以直接拿来使用,于是先定义个类型萃取器:
- template<typename Container>
- struct typeFromContainer
- {
- using type = typename Container::value_type;
- };
-
- template<typename T, size_t N>
- struct typeFromContainer
- {
- using type = T;
- };
-
- template<typename T>
- struct typeFromContainer
- {
- using type = T;
- };
函数修改为:
- #include
- #include
-
- template <typename Container>
- void func(Container& t, const char* pMessage)
- {
- using type = typename typeFromContainer
::type; - std::cout << pMessage << boost::typeindex::type_id_with_cvr
().pretty_name() << std::endl; - }
测试代码为:
- int main()
- {
- std::vector<int> array4;
- func(array4, "array4 value type is: ");
-
- int array1[5] = {0, 1,3,4,8};
- func(array1, "array1 value type is: ");
-
- std::initializer_list<int> intArray{ 9, 10, 33,44 };
- func(intArray, "intArray value type is: ");
-
- std::array<int, 5> arArray{ 1,2,555,666,777888 };
- func(arArray, "arArray value type is: ");
-
- std::string strArray("32095235252");
- func(strArray, "strArray value type is: ");
-
- const int array2[6] = { 2,3,4,5,6,7 };
- func(array2, "array2 value type is: ");
-
- std::list<int> list1;
- func(list1, "list1 value type is: ");
-
- return 0;
- }
输出:
- array4 value type is: int
- array1 value type is: int
- intArray value type is: int
- arArray value type is: int
- strArray value type is: char
- array2 value type is: const int
- list1 value type is: int
评论记录:
回复评论: