Недавно я купил новый эффективный современный С++ от Scott Meyers и прочитал его сейчас. Но я сталкиваюсь с одним, что меня полностью задевает.
В пункте 5 Скотт говорит, что использование auto
- отличная вещь. Он сохраняет типизацию, дает в большинстве случаев правильный тип и может быть невосприимчивым к несоответствиям типа. Я полностью понимаю это и думаю, что auto
тоже хорошо.
Но затем в пункте 6 Скотт говорит, что каждая монета имеет две стороны. А также могут быть случаи, когда auto
выводит совершенно неправильный тип, например. для прокси-объектов.
Возможно, вы уже знаете этот пример:
class Widget;
std::vector<bool> features(Widget w);
Widget w;
bool priority = features(w)[5]; // this is fine
auto priority = features(w)[5]; // this result in priority being a proxy
// to a temporary object, which will result
// in undefined behavior on usage after that
// line
До сих пор так хорошо.
Но решение Скотта - это так называемая "явно типизированная идионизация инициализатора". Идея состоит в том, чтобы использовать static_cast для инициализатора следующим образом:
auto priority = static_cast<bool>(features(w)[5]);
Но это не только приводит к более типизации, но также явно указывается тип, который должен быть выведен. Вы потеряли оба преимущества auto
по явному заданному типу.
Может ли кто-нибудь сказать мне, почему выгодно использовать эту идиому?
Прежде всего, чтобы разобраться, мои вопросы направлены на то, почему я должен написать:
auto priority = static_cast<bool>(features(w)[5]);
вместо:
bool priority = features(w)[5];
@Sergey поднял ссылку на хорошую статью на GotW об этой теме, которая частично отвечает на мой вопрос.
Guideline: рассмотрите объявление локальных переменных auto x = type {expr}; когда вы хотите явно передать тип. Это самодокументируется, чтобы показать, что код явно запрашивает преобразование, он гарантирует, что переменная будет инициализирована, и она не позволит случайное неявное сужение преобразования. Только когда вы хотите явно сузить, используйте() вместо {}.
Что в основном приводит меня к соответствующему вопросу. Какую из этих четырех альтернатив я должен выбрать?
bool priority = features(w)[5];
auto priority = static_cast<bool>(features(w)[5]);
auto priority = bool(features(w)[5]);
auto priority = bool{features(w)[5]};
Номер один по-прежнему мой любимый. Это менее типичное и явное, как три других.
Точка об гарантированной инициализации действительно не выполняется, так как я все равно объявляю переменные не раньше, чем я могу их каким-то образом инициализировать. И другой аргумент о сужении в быстром тесте не получился хорошо (см. http://ideone.com/GXvIIr).