C++ auto
C语言时代auto是栈上的自动变量的意思。如果没书写,默认就是auto
auto int i; //C语言。等价于 int i;
C++11开始后,auto被引入了。上述语句就是非法的,因为auto有自动推导类型的意思,此时就不能手动指定类型了。
int a; int& refa=a; auto b = refa; // b的类型是int,不是int&
C++的auto推导,b被推导为int。如果我们想让b的类型与初始化表达式的类型一致,auto将不能胜任。
不管是auto b = expr; auto& b = expr;auto&& b = expr;...不管怎么写,都不能每次都让b的类型恰好等于expr表达式的类型。(有相等的情况)
只有引入decltype关键字后,提取和书写expr表达式类型才称为可能。代码如下:
decltype(1 + 2 + 3) c1 = 1 + 2 + 3; //c1类型是1+2+3的类型 int a = 10; int& refa = a; decltype(a) c0 = a; //c0类型等于a的类型,等于int decltype(refa) c1 = refa; //c1类型等于refa类型,等于int&
decltype(1+2+3) c1 = 1+2+3; 比较书写繁琐, C++17引入了decltype(auto). 可以理解为,编译器为我们把其中的auto替换为expr
decltype(auto) c1 = 1 + 2 + 3; //被替换成(隐含的自动扩展代码) decltype(1 + 2 + 3) c1 = 1 + 2 + 3;
decltype(auto)可应用于模板函数返回值。代码如下:
template <typename T1, typename T2> decltype(t1 + t2) add_fail_(T1 t1, T2 t2) //因编译器工作方式,无法成立 { return t1 + t2; } template <typename T1, typename T2> auto add(T1 t1, T2 t2) -> decltype(t1 + t2) //OK { return t1 + t2; } //或者 template <typename T1, typename T2> decltype(auto) add3(T1 t1, T2 t2) //OK { return t1 + t2; }
auto可用于结构化绑定,例如:
struct S { int i; float j; bool k; }; int main() { int a[3]{ 1,2,3 }; //auto [x, y, z] = a; //等价于 int x = a[0]; int y = a[1]; int z = a[2]; auto& [x, y, z] = a; //等价于 int& x = a[0]; int& y = a[1]; int& z = a[2]; x = 10; S s{ 1,2.0,true }; auto& [x, y, z] = s; //等价于 int& x = s.i; int& y = s.j; int& z = s.k; x = 10; }
auto用于lamda表达式:
int main() { auto lambda = [](int& x) { x += 3; }; std::vector<int> vec{ 1,2,3,4,5,6,7 }; std::for_each(vec.begin(), vec.end(), lambda); }
auto用于template<auto > 。考虑如下应用,在MPL实践中,需要采取int2type技术,就是把文字常量类型化。代码如下:
template<int n> struct typlized_int{ using T = int; constexpr static int data = n; }; template<short n> struct typlized_short{ using T = short; constexpr static short data = n; }; template<char n> struct typlized_char{ using T = char; constexpr static char data = n; }; int main() { std::cout << typlized_int<5>::data; }
我们发现了可以合并的冗余代码,typlized_xxx很相似。就改造成:
template<typename T ,T n> struct typlized{ constexpr static T data = n; }; int main() { std::cout << typlized<int,5>::data; std::cout << typlized<char,'a'>::data; }
非常好,代码冗余大大的减少。但是还有个问题,typlized<char,'a'>中的char和‘5’是不是很冗余?能否让编译器根据‘a’自动推导出char呢?
答案是有的,在C++17中,可以这样写:
template<auto n> struct typlized{ constexpr static decltype(n) data = n; }; int main() { std::cout << typlized<5>::data; std::cout << typlized<'a'>::data; }
推导成功!这就是template<auto>.