标签:类型推导 const form 区别 推导 error int list() src
上篇文章讲了模板参数的推导规则,其实auto的推导规则跟模板参数的推导基本上一样的,都是推导参数嘛。比如上篇文章的模板基本结构是:
template<typename T>
void f(ParamType param);
......
f(expr);
编译器使用expr来推断ParamType
和T
。
那么对应在auto推导中,auto就对应了T
,变量的type specifier
就是ParamType
:
auto x = 27;
const auto cx = x;
const auto& rx = x;
这里,cx的type specifier
就是const auto
,rx的type specifier
就是const auto&
.
我们可以想象成在推导auto类型时,编译器就是在做一次模板参数类型推断:
template<typename T>
void func_for_x(T param);
func_for_x(27);
template<typename T>
void func_for_cx(const T param);
func_for_cx(x);
template<typename T>
void func_for_rx(const T& param);
func_for_rx(x);
在模板参数推导中,我们根据ParamType
将情况分成了三类。在auto推导中,我们同样可以根据type specifier
来分成三种情况:
type specifier
是一个指针或者引用,但不是universal reference(或者叫forwarding references).type specifier
是一个universal reference。type specifier
既不是指针也不是引用。const auto& rx = x;
上面分析过,不再赘述。
auto&& uref1 = x; // x is int and lvalue, so uref1‘s type is int&
auto&& uref2 = cx; // cx is const int and lvalue, so uref2‘s type is const int&
auto&& uref3 = 27; // 27 is int and rvalue, so uref3‘s type is int&&
auto x = 27;
const auto cx = x;
注意这个Case的情况,假如我们有个函数返回引用,我们使用auto接收返回值,如果我们想改变函数的返回值,那么必须用auto&,而不是auto,因为这里和函数模板参数推断规则一样,是pass-by-value,会忽略引用、const和volatile:
int x = 50;
int &f() { return x; }
int main() {
auto a1 = f();
a1 = 10; // x = 50
auto &a2 = f();
a2 = 20; // x = 20
return 0;
}
在函数模板参数推断中讨论了数组和函数作为模板参数的推断情况,在auto类型推断中情况也是相同的:
const char name[] = "R. N. Briggs";
auto arr1 = name; // arr1‘s type is const char*
auto& arr2 = name; // arr2‘s type is const char (&)[13]
void someFunc(int, double);
auto func1 = someFunc; // func1‘s type is void (*)(int, double)
auto& func2 = someFunc; // func2‘s type is void (&)(int, double)
从C++11起有4种选择可以定义一个整形变量:
auto x1 = 27;
auto x2(27);
auto x3 = { 27 };
auto x4{ 27 };
最后两种是C++11的新特性:统一初始化(uniform initialization),就是这个造成了模板参数推导和auto类型推导的最大区别 :
auto x1 = 27; // type is int, value is 27
auto x2(27); // type is int, value is 27
auto x3 = { 27 }; // type is std::initializer_list<int>, value is { 27 }
auto x4{ 27 }; // type is std::initializer_list<int>, value is { 27 }
特殊点在于:如果使用uniform initialization
来进行auto类型推断,那么最终auto推断出的结果是std::initializer_list<int>
所以下面的代码会编译报错:
template <typename T>
void f(T param);
f({11, 23, 9});
但是如果指定ParamType
为std::initializer_list<T>
,则可以正确的推断T的类型:
template<typename T>
void f(std::initializer_list<T> initList);
f({ 11, 23, 9 }); // T deduced as int, and initList‘s type is std::initializer_list<int>
在C++14中,允许将函数返回值和lambda参数声明为auto,但是在这种情况下,auto的类型推断使用的是模板参数类型推断规则:
auto createInitList() {
return { 1, 2, 3 }; // error: can‘t deduce type for { 1, 2, 3 }
}
std::vector<int> v;
…
auto resetV = [&v](const auto& newValue) { v = newValue; }; // C++14
…
resetV({ 1, 2, 3 }); // error! can‘t deduce type for { 1, 2, 3 }
(完)
朋友们可以关注下我的公众号,获得最及时的更新:
c++11-17 模板核心知识(六)—— 理解auto推导规则
标签:类型推导 const form 区别 推导 error int list() src
原文地址:https://www.cnblogs.com/zhangyachen/p/14013607.html