Как автоматически выводить тип?

У меня есть несколько случаев использования auto:

auto s = expr;          //s is always lvalue
auto & s = expr;        //s is always lvalue reference? What if expr is rvalue?
auto && s = expr;       //s is perfectly forwarded

Они правда? Если нет, то почему?

2 ответа

Решение

Дип правильно, и я хотел бы уточнить.

Прежде всего, вывод из dyp:

Тип выведенный для auto в объявлении переменной определяется правила вывода шаблонов аргументов, см. [dcl.spec.auto]/6; с одним исключением: если инициализатор представляет собой список фигурных скобок, выведенный тип std::initializer_list,

Я объясню.

Первый,

auto s = expr;

Это то же самое, что выводить T от expr,

template<class T>
void f(T s);

f(expr);

Правило вывода аргументов шаблона довольно сложное, так как вы имеете дело только с lvalue и rvalue, давайте сосредоточимся на этом.

Вывод аргумента шаблона происходит путем сравнения типа параметра шаблона (назовите его P, в этом случае P является T) и соответствующий аргумент (назовите его Aв данном случае тип expr).

От 14.8.2.1,

Если P не ссылочный тип:

- Если A является типом массива, тип указателя, полученный стандартным преобразованием массива в указатель (4.2), используется вместо A для вывода типа; иначе,

- Если A является типом функции, то для определения типа используется тип указателя, созданный стандартным преобразованием функции в указатель (4.3); иначе,

- Если A является cv-квалифицированным типом, cv-квалификаторы верхнего уровня типа A игнорируются для вывода типа.

Так что если expr является массивом или функцией, она будет рассматриваться как указатели, если expr имеет cv-qualification (const и т.д.), они будут игнорироваться.

Если P это cv-квалифицированный тип, cv-квалификаторы верхнего уровня Pтип игнорируется для вывода типа.

Это на самом деле говорит:

const auto s = expr;

s это const переменная, но для вывода типа для auto цели, const будут удалены

Таким образом, из приведенных выше правил, auto будет выведен на тип expr (после некоторого преобразования типа, указанного выше).

Обратите внимание, что когда выражение является ссылкой на T, он будет скорректирован до T до предварительного анализа.

Так что expr is - тип значения rvalue, lvalue или lvalue/rvalue - тип auto всегда будет тип expr без ссылки.

auto s1 = 1; //int
int &x = s1;
auto s2 = x; //int
int &&y = 2;
auto s3 = y; //int

Во-вторых, давайте посмотрим на

auto &s = expr;

Это будет так же, как

template<class T>
void f(T &s);

f(expr);

Дополнительное правило из стандарта выглядит следующим образом:

Если P является ссылочным типом, тип, на который ссылается P используется для вывода типа.

Так что вычет авто будет точно таким же, как и без &, но после auto тип вычитается, & добавляется в конец auto,

//auto &s1 = 1; //auto is deducted to int, int &s1 = 1, error!
const auto &s1 = 1; //auto is deducted to int, const int &s1 = 1; ok!
const int &x = s1;
auto &s2 = x; //auto is int, int &s2 = x; ok!
int &&y = 2;
auto &s3 = y; //auto is int, int &s3 = y; ok! 

Обратите внимание, что последний y это значение. Правило C++: именованная ссылка rvalue является lvalue.

И, наконец:

auto &&s = expr;

Это, несомненно, так же, как

template<class T>
void f(T &&s);

f(expr);

Одно дополнительное правило из стандартного:

Если P является rvalue ссылкой на неквалифицированный cv параметр шаблона, а аргумент является lvalue, вместо него используется тип "lvalue ссылка на A" A для вывода типа.

Это на самом деле говорит, что если expr является rvalue, правило будет таким же, как и во втором случае (lvalue case), но если expr является lvalue, тип A будет lvalue ссылкой на A,

Примечание из предыдущего объяснения, A никогда не является ссылкой, потому что тип выражения никогда не является ссылкой. Но для этого особого случая (auto &&, а также A является lvalue), ссылка на A должны быть использованы независимо expr сам по себе является ссылочным типом или нет.

Пример:

auto &&s1 = 1; //auto is deducted to int, int &&s1 = 1, ok!
int x = 1;
auto &&s2 = x; //x is lvalue, so A is int &, auto is deducted to int &, int & &&s2 = x; ok!
int &&y = 2;
auto &&s3 = y; //y is lvalue, auto is int &, int & &&s3 = y; ok!

Поскольку никто не дает ответа, и я теперь вроде понимаю (спасибо @dyp), я бы просто опубликовал ответ сам. Укажите ошибку, если есть:

auto s = expr;

Если expr является lvalue, prvalue или любой ссылкой, s всегда lvalue и копия сделана.

auto& s = expr;

Если expr является lvalue, ссылкой lvalue или ссылкой rvalue, s это ссылка на значение. Если expr Это prvalue, это ошибка и не законно.

auto&& s = expr;

s отлично переадресован (rvalue станет ссылкой на rvalue и свернется).

Другие вопросы по тегам