c++类型推导
传统c和c++中,无论什么变量都应该先去声明其类型,指出其类型后才能进行下一步操作,这通常会花费很多无意义的时间。
c++11引入了auto
和 decltype
这两个关键字实现了类型推导,让编译器来操心变量的类型。这使得 C++ 也具有了和其他现代编程语言一样,某种意义上提供了无需操心变量类型的使用习惯。
auto
auto关键字可以对一些变量进行类型推导,简单使用样例如下:
int a=10; auto b=a;
我们经常在对迭代器或循环中的变量声明中使用它,如
set<int> a;
... for(auto it = a.begin();it != a.end();++it){...} vector<int>b; ... for(auto num:b){...}
auto的类型推导几乎和模板类型推导一致,除了一种特殊情况,即对花括号的推导。
auto test={1,2,3}; //test被推导为std::initializer_list<int> template<typename T> func(T type) { ... } func({1,2,3}); //错误,无法推导出T的类型
有关auto的类型推导(与模板推导相同)需注意以下几点:
如果auto不是引用类型(即只用auto推导,而非auto&或auto&&),那么推导会忽略推导对象的引用部分和对自身的const或volatile修饰。
int x1=1; const int x2=1; int& x3=x1; const char* const x4 = "test"; auto t1=x1; //t1类型为int auto t2=x2; //t2类型为int auto t3=x3; //t3类型为int auto t4=x4; //t4类型为const char*
vs2022运行结果:
t1-t3通过以上规则容易理解,对于t4,x4是一个指向const char的指针常量,对于x4来说,其自身的常量性修饰是第二个const,即第二个const限制了其自身值无法改变,因此类型推导会忽略第二个const,最终推导出t4的类型为const char*
对于auto& 和auto&& ,详见万能引用文章
decltype
decltype关键字可以对一些表达式类型进行推导,例如:
auto x=1; //x被推导为int auto y=2; decltype(x+y) z; //z被推导为int
if (std::is_same<decltype(x), int>::value) std::cout << "type x == int" << std::endl; //对x的类型进行判断
尾返回类型推导
c++11支持对函数返回类型进行推导,方法如下所示:
template<typename T, typename U> auto add2(T x, U y) -> decltype(x+y){ return x + y; }
我们甚至可以配合std::future访问异步操作结果来实现对函数类型的推导(线程池中常见):
template <typename F, typename... Args> auto submit(F&& f, Args&&... args) -> std::future<decltype(std::forward<F>(f)(std::forward<Args>(args)...))> { using return_type = decltype(f(args...)); auto task_ptr = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...)); auto task_future = task_ptr->get_future(); auto wrapper_func = [task_ptr]() { (*task_ptr)(); }; schedule_by_id(std::move(wrapper_func)); return task_future; }
注意上述函数返回的是一个std::future对象即期约对象,对返回对象使用get方法即可获取函数 f 即decltype(std::forward<F>(f)(std::forward<Args>(args)...))类型的结果。
在c++14中支持直接auto推导返回值类型,无需尾返回推导。