Какова цель использования auto при объявлении переменной static_cast <> ()? - PullRequest
4 голосов
/ 27 апреля 2020

Скотт Мейерс в своем «Эффективном современном C ++: 42 Specifi c Пути улучшения вашего использования C ++ 11 и C ++ 14» обсуждает использование auto в различных контекстах. Он подчеркивает, что иногда auto выводит неверный тип, потому что обычно разработчик будет использовать (возможно, неосознанно) неявное преобразование, как здесь:

std::vector<bool> vec = {true, false};
bool a = vec[0]

при использовании auto, например:

std::vector<bool> vec = {true, false};
auto a = vec[0]

даст a равным std::vector<bool>::reference, поэтому автор предлагает разыграть его перед назначением:

auto a = static_cast<bool>(vec[0])

, и я не могу понять, почему я должен использовать auto и static_cast<> в этом Кстати, если я могу просто рассчитывать на неявное преобразование. Я подумал, что, может быть, это для того, чтобы подчеркнуть тот факт, что происходит конверсия (чтобы отметить это явно), но это все еще выглядит для меня излишним. В чем будет преимущество такого решения?

Ура!

Ответы [ 2 ]

3 голосов
/ 27 апреля 2020

Примите это за посылку: вы хотите использовать auto как можно больше, тогда

std::vector<bool> vec = {true, false};
auto a = vec[0];

сделает неожиданное, в то время как:

auto a = static_cast<bool>(vec[0]);

получит вас bool. Я не думаю, что смысл в том, чтобы сказать: «Используйте static_cast вместе с auto как можно больше». Но скорее: «Если вы хотите использовать auto почти всегда, то иногда вам нужно добавить static_cast»

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

В этом случае да, но тогда вы не используете auto. Также рассмотрим случай, когда не вы использовали auto. Допустим, вам дана лямбда, определенная как:

auto foo = [](auto x){};

Вы не можете изменить ее подпись, поэтому вам нужно использовать static_cast, если вы хотите вызвать ее с помощью vec[0] и получить правильный тип .

Также учтите, что если вы действительно следуете AAA (почти всегда автоматически), тогда вы действительно объявите все переменные как auto. Это помогает никогда не забывать инициализировать переменную. Если при необходимости вы вернетесь к

bool a = vec[0];

, это в первую очередь лишит смысла применение ААА. Вы хотите быть последовательным и не выбирать auto против явного типа в зависимости от инициализатора.

3 голосов
/ 27 апреля 2020

В ряде случаев static_cast может помочь уменьшить как неоднозначности компилятора, так и неоднозначности читателя при использовании с auto.

В частности, при рассмотрении std::vector<bool> в примере, я могу подумать из двух таких случаев:

  • Если бы это было передано в шаблон функции, который выводит аргумент, вы бы скорее decltype(a) предпочли бы bool, чем какой-то тип std::__vector_bool_reference_wrapper, или
  • Если a были переданы функции с сигнатурой, которая принимает bool& или bool*, вы бы хотели, чтобы это был правильный тип - поскольку неявные преобразования не произойдут

Приведенные выше случаи относятся ко всему, что может иметь неявные преобразования, а не только к bool / reference-wrapper.

Кроме того, дела становятся более интересными с другими типами.

Указатели:

nullptr имеет тип decltype(nullptr), который также называется псевдонимом std::nullptr_t. Это не любого типа T*. Это означает, что вы не можете написать такой код, как:

auto p = nullptr;
...
p = &a; // compile-error!

Но вместо этого потребуется:

auto p = static_cast<T*>(nullptr);
...
p = &a; // works!

Непреднамеренные рекламные акции

Непреднамеренные рекламные акции могут производить неожиданные ошибки. Если код использует auto и полагается на целочисленное переполнение, без явного указания на типы, можно непреднамеренно произвести целочисленное продвижение - что может предотвратить возникновение этого переполнения. Это может привести к незначительным ошибкам в некотором коде.

То же самое, вероятно, возможно с продвижением float / double, хотя мне труднее думать о случае, когда такой случай будет отрицательным.

Непреднамеренные повышения могут также вызывать сбои компиляции, если результат передается функции, которая ожидает ссылку или указатель на T другого типа, чем продвигаемый тип (аналогично примеру vector<bool> выше).


Я уверен, что существуют другие случаи, когда static_cast значимо при использовании с auto, но в целом случаи, которые приходят на ум, имеют дело со строгой типизацией, которая идет с перегрузкой разрешение и вычет типа шаблона.

Кроме этого, могут также быть случаи, когда static_cast просто помогает общей читаемости сложных функций, которые используют много auto

...