Может ли автоматическая дедукция добавить неявную константность?

Рассмотрим следующий пример:

#include <iostream>
#include <string>

struct foo { std::string value; };
inline foo bar() { return { "42" }; }

std::string my_func() {
    auto &x = bar();
    ^^^^^^^^^^^^^^^^
    return x.value;
}

int main() {
  std::cout << my_func() << std::endl;  
}

Компиляция как GCC, так и CLANG выдает, скорее всего, ту же ошибку:

ошибка: недопустимая инициализация неконстантной ссылки типа "foo&" из rvalue типа "foo"

Однако, к моему удивлению, он отлично компилируется и работает в VC++2015.

  • Является ли это ошибкой VC++ 2015?
  • Предписывает ли стандарт, что auto может неявно добавлять constness к объекту, когда оператор делает программу неправильно сформированной?

person 101010    schedule 05.11.2015    source источник


Ответы (3)


Является ли это ошибкой VC++ 2015?

Стандарт позволяет реализациям принимать некорректный код в качестве расширений. Однако реализациям по-прежнему требуется выдавать диагностику (что может просто означать «выдавать предупреждение при включении определенных флагов»).

Предписывает ли стандарт, что auto может неявно добавлять константу к объекту, когда оператор делает программу неправильно сформированной?

Нет, стандарт требует, чтобы auto вывод использовал те же правила, что и вывод аргумента шаблона (за исключением списков инициализаторов). Если T& не примет, то auto& не примет.

person Brian Bi    schedule 05.11.2015

Нет, auto не может добавить постоянства. Однако в MSVC++ всегда было расширение, позволяющее неконстантным ссылкам lvalue связываться с rvalue.

Я думаю, вы можете отключить это расширение с помощью переключателя /Za.

person M.M    schedule 05.11.2015

Является ли это ошибкой VC++ 2015?

Редмондские ответчики часто называют это «фичей», но это совершенно глупая ошибка в этом бардаке компилятора (исправимая с помощью /Za). Давайте посмотрим, почему...

auto &x = bar();

Итак, вы звоните bar(), нет? Это создает rvalue, то есть объект без адреса. Теперь вы не можете привязать ссылку lvalue (объект, адрес которого можно получить) (он же: &) к rvalue. Пока что это причина того, что ваш код незаконен.

Однако в языке C++ есть специальное правило, позволяющее ссылке const lvalue привязываться к rvalue, эффективно продлевая время ее жизни. Таким образом, это будет действительный код...

const auto &x = foo();

Изменить: кстати...

Предписывает ли стандарт, что auto может неявно добавлять константу к объекту, когда инструкция делает программу неправильной?

Говоря нестандартной терминологией/простым английским языком, если T& будет отклонено, то же самое будет и с auto&. Квалификаторы CV (const и volatile) не автоматически выводятся из auto.

Надеюсь, это пролило на вас свет!

person 3442    schedule 05.11.2015
comment
CV-квалификаторы (const и volatile) не выводятся автоматически из auto. Не совсем. const int c = 1; auto& d = c; /* OK, d is const int & */ Он не создает cv-квалификаторы из воздуха, но если инициализатор имеет cv-квалификацию, он совершенно счастлив вывести его - person T.C.; 06.11.2015
comment
@T.C. Я бы добавил, что он работает даже с rvalue: auto& d = std::move(c) будет компилироваться. Но вы не так часто видите константные rvalue. - person Brian Bi; 06.11.2015
comment
О чем ты? В настоящее время я работаю с GNU/Linux и у меня есть Mac, и тем не менее я должен защищать Редмонд, потому что компиляторы могут принимать некорректный код в качестве расширений (за исключением того, что может потребоваться предупреждение, как это было упомянул). Стоит ли это конкретное расширение, это отдельная тема. Например, разработчики GCC были так же счастливы предоставлять расширения, как и любая другая команда компиляторов — помните сигнатуры C++? Я не знаю ни одного чистого стандартного компилятора C++, даже по умолчанию. - person Arne Vogel; 06.11.2015
comment
@ArneVogel: GNU/Linux, конечно;). Я хочу сказать, что о большинстве этих функций сообщалось как об ошибках задолго до того, как они были заявлены как функции, не говоря уже о том, что они почти не документированы. GCC по крайней мере документирует __attribute__(())... - person 3442; 06.11.2015