Каковы правила вывода типов для 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. Вывод типа объекта (v1, v2 и v3) после добавления (*)

Итак, два моих вопроса:

  1. К чему будет выводиться auto без (*) ?
  2. Будет ли v2 указателем на int (int*) и v3 на указатель (int**)?

person Laith    schedule 15.04.2016    source источник


Ответы (4)


Если вы знаете вывод шаблонного типа, вы будете знать почти все, что нужно для 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, что позволяет использовать инициализацию прямого списка с автоматическим (ожидаемый стандарт)

person Andreas DM    schedule 15.04.2016
comment
Я понимаю, что auto работает точно так же, как шаблон... Я на самом деле понимаю большую часть вывода типа auto и template, но немного меня смущает ( auto* ), и если бы я расширил свой вопрос, я бы спросил о ( T * ) из шаблона тоже :) ... и, к сожалению, у меня нет библиотеки boost :( но +1 ... спасибо - person Laith; 15.04.2016

auto выведет указанное выражение в тип cv-qualified. auto* выведет тип с указанием типа, на который указывает выражение типа, если выражение является указателем, и не сможет скомпилироваться в противном случае.

Для приведенных примеров фактический тип v будет pointer to int, то же самое с v2, а для v3 будет pointer to pointer to int.

Если бы ваш первый пример был написан как auto v1 = &px, тип v1 остался бы прежним.

person SergeyA    schedule 15.04.2016

Вы можете использовать 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 --> указатель на указатель на целочисленную переменную

person g4ur4v    schedule 15.04.2016

Процесс вывода аналогичен параметру шаблона. Если я сделаю:

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

Тип b будет int*. И писать:

auto b = &a;

Приведет к тому же типу, int*. В вашем примере компилятор каким-то образом добавит недостающую звездочку. Но проще всего было бы просто написать auto

person Guillaume Racicot    schedule 15.04.2016