auto* 的类型推导规则是什么?

What are the type deduction rules for auto*?

auto*的类型推导规则是什么?

考虑以下几点:

int x = 64;
int* px = &x;

auto* v1 = &x;    // auto => ???    ok v1 is int* ...
auto* v2 = px;    // auto => ???    is v2 int*  ?
auto* v3 = &px;   // auto => ???    is v3 int** ?

如果我们将类型推导分为两步,只是为了澄清我的问题:

  1. 在没有 (*) 的情况下推导“auto”本身的类型 ... 然后
  2. 在添加 (*)
  3. 之后推断对象的类型 (v1v2v3)

所以我的两个问题是:

  1. 如果没有 (*),auto 会推导出什么?
  2. v2 会指向 int (int*) 并且 v3 会指向指针 (int**) 吗?

auto 将推导出给定表达式的 cv 限定类型。 auto* 将推导出表达式指向的类型的 cv 限定类型 - 如果表达式是指针 - 否则将无法编译。

对于给定的示例,v 的实际类型将是 pointer to int,与 v2 相同,对于 v3,它将是 pointer to pointer to int

如果您的第一个示例写成 auto v1 = &px,v1 的类型将保持不变。

推导过程与模板参数相同。如果我这样做:

int a = 0;
auto* b = &a;

b 的类型将为 int*。并写作:

auto b = &a;

将产生相同的类型,int*。 在您的示例中,编译器将以某种方式添加缺失的星号。但最简单的形式是只写 auto

您可以使用 typeid 来回答您的问题。

#include <iostream>
#include <typeinfo>
using namespace std;

int main() {
    // your code goes here
    int x = 64;
    int* px = &x;

    auto* v1 = &x;   
    auto* v2 = px;    
    auto* v3 = &px;   
    cout<<typeid(v1).name()<<endl;
    cout<<typeid(v2).name()<<endl;
    cout<<typeid(v3).name()<<endl;
    return 0;
}

输出:

Pi
Pi
PPi

Pi --> 指向整型变量的指针

PPi --> 指向整数变量的指针

如果您了解 模板类型推导 ,您将几乎了解 auto 类型推导 的所有内容。因为自动类型推导像模板类型推导一样工作。

当使用 auto 声明变量时,auto 在模板中充当 T,类型说明符充当 参数类型 :

const auto i = 20;

将转换为:

template<typename T>
void func(const T param) { ... }
//        ^^^^^^^

并参考:

const auto& j = i;

转换为:

template<typename T>
void func(const T& param) 
//        ^^^^^^^^

有了指针,也一样:

auto* v1 = &x;

变成

template<typename T>
void func(T* param)

因为x是一个int,那么auto* == int*
auto* v2 = px; 也是 int*

现在,你有第三个:

auto* v3 = &px;

变成 int** 因为你正在获取指针的地址。

template<typename T>
void func(T** param)
//        ^^^

查看 auto 类型的一种简便方法是使用其他人提到的 typeid() 函数。
但我喜欢使用 <boost/type_index.hpp> 来正确显示类型:

#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
using namespace boost::typeindex;

int main()
{
    int x = 64;
    int* px = &x;

    auto* v1 = &x;
    auto* v2 = px;
    auto* v3 = &px;
    cout << type_id_with_cvr<decltype(v1)>().pretty_name() << '\n';
    cout << type_id_with_cvr<decltype(v2)>().pretty_name() << '\n';
    cout << type_id_with_cvr<decltype(v3)>().pretty_name() << '\n';
}

输出:

int*
int*
int**

自动类型推导和模板类型推导有一个重要区别,即std::initializer_list<>

考虑这些例子:

auto i = 1;   // int
auto j(1);    // int
auto k = { 1 }// std::initializer_list<int> !
auto l { 1 }  // std::initializer_list<int> !

如您所见,将大括号初始化程序与 auto 一起使用可能会很麻烦。
但是,您可以在大括号之前手动编写类型以确保类型正确,但我不明白其中的意义:

auto i = int{ 1 }; // type is int

Clang 3.8 中已经实现了 new auto rules,这使得使用直接列表初始化和自动(即将发布的标准)成为可能