现在有这样一个函数:
template <typename Container>
Void func(Container t, const char* pMessage){ }
需要从容器 t 中获取元素的类型,首先我们想到的是:?
#include <iostream>
#include <boost/type_index.hpp>
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 <iostream>
#include <boost/type_index.hpp>
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 <iostream>
#include <boost/type_index.hpp>
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
上面的代码都是基于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<T[N]>
{
using type = T;
};
template<typename T>
struct typeFromContainer<T[]>
{
using type = T;
};
函数修改为:
#include <iostream>
#include <boost/type_index.hpp>
template <typename Container>
void ?func(Container& t, const char* pMessage)
{
using type = typename typeFromContainer<Container>::type;
std::cout << pMessage << boost::typeindex::type_id_with_cvr<decltype(TYPE)>().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
?
?