auto 让编译器通过初始值来推算变量的类型。显然,auto 定义的变量必须有初始值:
auto item = val1 + val2; // item 初始化为 val1 和 val2 相加的结果
使用 auto 也能在一条语句中声明多个变量。因为一条声明语句只能有一个基本数据类型:
auto i = 0, *p = &i; // 正确:i 是整数、p 是整型指针
auto sz = 0, pi = 3.14; // 错误:sz 和 pi 的类型不一致
** 复合类型、常量和 auto**
int i = 0, &r = i;
auto b = r; // 编译器以引用对象的类型作为 auto 的类型
auto 一般会忽略掉顶层 const,同时底层 const 则会保留下来,比如当初始值是一个指向常量的指针时:
int i = 0;
const int ci = i, &cr = ci;
auto b = ci; // b 是一个整数(ci 的顶层 const 特性被忽略)
auto c = cr; // c 是一个整数(cr 是 ci 的别名,ci 本身是一个顶层 const)
auto d = &i; // d 是一个整型指针(整数的地址就是指向整数的指针)
auto e = &ci; // e 是一个指向整数常量的指针(对常量对象取地址是一种底层 const)
如果希望推断出的 auto 类型是一个顶层 const,需要明确指出:
const auto f = ci; // f 是 const int
还可以将引用的类型设为 auto,此时原来的初始化规则仍然适用:
auto &g = ci; // g 是一个整型常量引用,绑定到 ci
//auto &h = 42; // 错误:不能为非常量引用绑定字面值
const auto &j = 42; // 正确:为常量引用绑定字面值
设置一个类型为 auto 的引用时,初始值中的顶层常量属性仍然保留。和往常一样,如果我们给初始值绑定一个引用,则此时的常量就不是顶层常量了。
要在一条语句中定义多个变量,切记,符号 & 和 * 只从属于某个声明符,而非基本数据类型的一部分,因此初始值必须是同一种类型:
auto k = ci, &l = i; // k 是整数,l 是整型引用
auto &m = ci, *p = &ci; // m 是对整型常量的引用,p 是指向整型常量的指针
//auto &n = i, *p2 = &ci; // 错误:i 的类型是 int 而 &ci 的类型是 const int
上述内容的测试代码如下:
#include <QCoreApplication>
#include <cxxabi.h>
#include <QDebug>
#include <typeinfo>
#include <iostream>
#include <string>
#include <memory>
#include <cstdlib>
namespace {
std::string demangle(const char* mangled)
{
int status;
std::unique_ptr<char[], void (*)(void*)> result(
abi::__cxa_demangle(mangled, nullptr, nullptr, &status), std::free);
return result.get() ? std::string(result.get()) : "error occurred";
}
template<class T>
void foo(T t) { std::cout << demangle(typeid(t).name()) << std::endl; }
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int i = 0;
const int ci = i, &cr = ci;
auto b = ci; // b 是一个整数(ci 的顶层 const 特性被忽略)
auto c = cr; // c 是一个整数(cr 是 ci 的别名,ci 本身是一个顶层 const)
auto d = &i; // d 是一个整型指针(整数的地址就是指向整数的指针)
auto e = &ci; // e 是一个指向整数常量的指针(对常量对象取地址是一种底层 const)
const auto f = ci; // f 是 const int
auto &g = ci; // g 是一个整型常量引用,绑定到 ci
// auto &h = 42; // 错误:不能为非常量引用绑定字面值
const auto &j = 42; // 正确:为常量引用绑定字面值
auto k = ci, &l = i; // k 是整数,l 是整型引用
auto &m = ci, *p = &ci; // m 是对整型常量的引用,p 是指向整型常量的指针
// auto &n = i, *p2 = &ci; // 错误:i 的类型是 int 而 &ci 的类型是 const int
foo(b);
foo(c);
foo(d);
foo(e);
foo(f);
foo(g);
foo(j);
foo(k);
foo(l);
foo(m);
foo(p);
return a.exec();
}
测试代码的输出结果如下:
int
int
int*
int const*
int
int
int
int
int
int
int const*
用于初始化
如果我们提供了一个括号包围的初始化器,就可以使用 auto 从此初始化器来推断我们想要分配的对象的类型。但是,由于编译器要用初始化器的类型来推断要分配的类型,只有当括号中仅有单一初始化器时才可以使用 auto:
auto p1 = new auto(obj); // p1 指向一个与 obj 类型相同的对象,该对象用 obj 进行初始化
auto p2 = new auto{a,b,c}; // 错误:括号中只能有单个初始化器
p1 的类型是一个指针,指向从 obj 自动推断出的类型。若 obj 是一个 int,那么 p1 就是 int;若 obj 是一个 string,那么 p1 是一个 string;依此类推。新分配的对象用 obj 的值进行初始化。
网友评论