Разница между const auto & и auto &, если объект ссылки является константным

// case 1
const int i = 42;
const auto &k = i;

// case 2
const int i = 42;
auto &k = i;

Нужно ли нам ключевое слово const перед auto в этом сценарии? В конце концов, ссылка (k) на автоматически выводимый тип будет включать верхний уровень const объекта (const int i). Поэтому я считаю, что k будет ссылкой на целое число, которое является константой (const int &k) в обоих случаях.

Если это правда, значит ли это, что const auto &k = i; в случае 1 заменяется компилятором просто как const int &k = i; (auto заменяется на int)? Тогда как в случае 2 auto заменяется на const int?


person Steve Cho    schedule 06.09.2018    source источник
comment
Возможный дубликат Как использовать auto с const и & в С++? (хотя у этого заголовок лучше, просто я бы убрал эти k).   -  person Daniel Langr    schedule 06.09.2018
comment
Оба похожи для компилятора. Но как человек-читатель, я предпочитаю первый.   -  person Jarod42    schedule 06.09.2018
comment
Интересно, кто нашел это неясным. В ясности нет недостатка, вы очень хорошо выразились.   -  person StoryTeller - Unslander Monica    schedule 06.09.2018
comment
@StoryTeller — сценарий обслуживания определил его и отправил в комнату SOCVR. Я предполагаю, что это ошибка типа I в сценарии. Вопрос был неправильно классифицирован и неправильно отклонен.   -  person jww    schedule 06.09.2018
comment
@jww - Вы говорите мне, что бот проголосовал?   -  person StoryTeller - Unslander Monica    schedule 06.09.2018
comment
@StoryTeller - Нет, я только говорю, что сценарий определил вопрос как потенциально проблемный. Я предполагаю, что человек выступил против вопроса после того, как он был опубликован в комнате.   -  person jww    schedule 06.09.2018
comment
@StoryTeller@jww, не могли бы вы пояснить, о чем вы, ребята, говорите? Я новичок в переполнении стека, поэтому я не слежу. кто-то сообщил о моем вопросе, потому что они думали, что это дубликат?   -  person Steve Cho    schedule 06.09.2018
comment
@SteveCho - Вы можете обратиться только к одному человеку с упоминанием (@). jww не пингуется. Что касается вашего вопроса, то SOCVR — это чат, в котором пользователи, заботящиеся о качестве контента, вместе удаляют плохой контент. Есть боты, которые читают новые сообщения и обращают на них внимание чата, если они кажутся плохими вопросами. Но это все еще люди, которым нужно отдать близкие голоса. jww и я обсуждали близкое голосование по твоему посту.   -  person StoryTeller - Unslander Monica    schedule 06.09.2018


Ответы (5)


Ключевое слово auto автоматически определяет тип переменной во время компиляции.

В первом случае auto уменьшается до int, а во втором — до const int. Итак, оба ваших случая сводятся к тому же коду, что и:

const int &k = i;

Однако лучше указать константу явно для лучшей читабельности и убедиться, что ваша переменная TRULY равна const.

person Praneeth Peiris    schedule 06.09.2018
comment
Это также означает, что я хочу, чтобы это была ссылка на константу, независимо от того, была ли она уже константой раньше, потому что то, было ли это константой раньше, на самом деле не имеет отношения к тому, хотите ли вы добавить константу сейчас. - person Lightness Races in Orbit; 06.09.2018

Вывод типа с auto работает так же, как вывод типа аргумента шаблона с несколькими исключениями, которые не применяются в данном примере. Следовательно

const int i = 42;
const auto& k1 = i; // same as const int& k1 = i;
auto& k2 = i; // same as (const int)& k2 = i;

Тем не менее, вероятно, более читабельно добавить квалификатор const.

Вот еще один пример, когда предпочтение краткости с помощью auto вводит в заблуждение:

int *i;
const auto k1 = i; // same as int* const k1 = i;
const auto *k2 = i;  // same as const int *k2 = i;

В первом случае объект, на который указывает i, можно модифицировать через k1, во втором — нельзя.

person lubgr    schedule 06.09.2018
comment
за некоторыми исключениями Можете ли вы привести пример? Я не знал, что есть какие-то различия :) - person Rakete1111; 06.09.2018
comment
@ Rakete1111 У вас может быть auto a = { 1, 2, 3 };, который выводит std::initializer_list<int>, но template<class T> void f(T&&) {} нельзя вызвать через f({1, 2, 3}). - person lubgr; 06.09.2018
comment
Ах, вот что ты имеешь в виду. Но нет никакой разницы в фактическом выводе, как выражение, которое выводится к двум разным типам с помощью auto и шаблонного вывода? - person Rakete1111; 06.09.2018
comment
@ Rakete1111 Нет, это меня бы очень обеспокоило :) Формулировка ответа вводит в заблуждение? - person lubgr; 06.09.2018
comment
Не за что, просто интересно :) - person Rakete1111; 06.09.2018

Есть небольшая разница: в первом случае auto будет выведено в const int, а во втором случае в int (как вы явно указали const).

состояния ссылок cpp

Ключевое слово auto может сопровождаться модификаторами, такими как const или &, которые будут участвовать в выводе типа. Например, при заданном const auto& i = expr; тип i точно совпадает с типом аргумента u в воображаемом шаблоне шаблона void f(const U& u), если вызов функции f(expr) был скомпилирован. Следовательно, auto&& может быть выведен либо как ссылка lvalue, либо как ссылка rvalue в соответствии с инициализатором, который используется в цикле for на основе диапазона.

Для вас это означает

// case 1
const int i = 42;   
const auto &k = i;   // auto -> int

// case 2
const int i = 42;
auto &k = i;  // auto -> const int

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

person user32434999    schedule 06.09.2018

Привет и добро пожаловать в переполнение стека.

Как показывает эта небольшая тестовая программа, независимо от того, как вы указываете тип k, компилятор никогда не позволит вам потерять константность i.

#include <iostream>
#include <type_traits>
#include <string>

#define XSTR(s) STR(s)
#define STR(s) #s

template<class T> 
struct type;

template<>
struct type<int>
{
    static std::string name() { return "int"; }
};

template<class T>
struct type<T&&>
{
    static std::string name() { return type<T>::name() + " &&"; }
};

template<class T>
struct type<T&>
{
    static std::string name() { return type<T>::name() + " &"; }
};

template<class T>
struct type<T const>
{
    static std::string name() { return type<T>::name() + " const"; }
};

#define REPORT_CONST(decl, var, assign) \
{ \
    decl var = assign; \
    do_it(STR(decl var = assign;), var); \
}

template<class Var> 
void do_it(const char* message, Var&&)
{
    std::cout << "case: " << message << " results in type: " << type<Var>::name() << '\n';
}

int main()
{
    const int i = 42;

    REPORT_CONST(const auto &, k, i);
    REPORT_CONST(auto &, k, i);
    REPORT_CONST(auto &&, k, std::move(i));
    REPORT_CONST(auto const &&, k, std::move(i));
    REPORT_CONST(int const&, k, i);
    // REPORT_CONST(int &, k, i); // error: binding reference of type 'int&' to 'const int' discards qualifiers
}

Ожидаемые результаты:

case: const auto & k = i; results in type: int const &
case: auto & k = i; results in type: int const &
case: auto && k = std::move(i); results in type: int const &
case: auto const && k = std::move(i); results in type: int const &
case: int const& k = i; results in type: int const &

http://coliru.stacked-crooked.com/a/7c72c8ebcf42c351

Обратите также внимание на распад именованных r-значений в l-значения.

person Richard Hodges    schedule 06.09.2018

Принятый ответ правильный, т.е. нет никакой разницы в отношении скомпилированного результата. Важно отметить, что версия auto& сочетает const-версию ссылки k с const-версией переменной i. Я подумал, что, поскольку вопрос озаглавлен «Разница между const auto & и auto &...», важно подчеркнуть здесь прагматическую разницу, в которой, если вы не поместите ключевое слово const, вы не можете гарантировать, что ссылка будет иметь эту cv-квалификацию. В некоторых случаях, когда это желательно, зачем оставлять на волю случая, что i останется const в будущем?

person Geezer    schedule 06.09.2018