Это вдохновлено сообщением Андреем Александреску.
Что такое pro и con для инициализации выражения следующими способами? Когда я должен отдать предпочтение другому?
auto v = expr;
T v = expr;
auto v(expr);
T v(expr);
auto v { expr };
T v {expr};
Это вдохновлено сообщением Андреем Александреску.
Что такое pro и con для инициализации выражения следующими способами? Когда я должен отдать предпочтение другому?
auto v = expr;
T v = expr;
auto v(expr);
T v(expr);
auto v { expr };
T v {expr};
auto v = expr;
auto v(expr);
Если в вашем коде либо вы не знаете тип expr
и хотите остаться родовым, либо в своем коде, то абсолютно ясно, какой тип expr
имеет (определение прямо в строке выше и т.д.), так что auto
не добавит путаницы.
Форма инициализации, parens или нет, не имеет значения (имеет отношение только к языковым юристам, поскольку есть тонкие различия). Используйте то, с чем вам комфортнее.
T v = expr;
T v(expr);
Если в вашем коде не ясно, что expr
(определение слишком далеко друг от друга и т.д.), или если вы не знаете тип expr
, но хотите, чтобы v
был типа T
. Используйте первую форму, если вы хотите продолжать работать с "видом стоимости", который имеет "expr" (т.е. Если expr
- строка, а T
- строковый тип). Если вы создаете совершенно новый вид значения (т.е. Widget
и expr
- цвет виджета), используйте вторую форму.
auto v { expr };
Никогда не используйте это в текущем С++ (и, вероятно, в течение ближайших нескольких лет). Он объявит v
как std::initializer_list<TypeOfExpr>
. Если вы этого хотите, используйте тип напрямую и запишите его. Это слишком тонко (и есть предложения для более-С++ 14, чтобы изменить этот факт, поэтому есть надежда, что вы можете написать это на С++ 17 или что-то в этом роде).
T v {expr};
Если вы хотите защитить себя от сужения конверсий (т.е. от 1000
до char
случайно), или если вы хотите инициализировать класс, у которого есть конструктор списка инициализаторов, или если у вас есть совокупность члена ( s) которого вы хотите инициализировать, используйте эту форму. Кроме того, вы можете использовать следующее, если вы имеете дело с конструктором списка инициализаторов, агрегированным или простым неклассовым типом
T v = { expr };
Я бы не использовал его для вызова произвольного конструктора. Я бы использовал следующую форму для
T v(expr);
Тем не менее, есть люди, которые предпочитают использовать для этого форму брекетов. Мне нравится точно знать, что делает мой код, поэтому, когда я хочу вызвать конструктор и не хочу случайным образом выполнять вызов конструктора компоновки или списка инициализации вместо этого, я использую parens вместо привязок.
auto v = expr; T v = expr;
отлично, но в автоматической версии может быть трудно понять тип expr
.
Например, в auto x = snafuscate();
, каков тип x
??
При наличии двусмысленности лучше явно указать тип правой стороны как: auto x = Gadget { snafuscate() };
...
auto v(expr);
и T v(expr);
- плохая идея, потому что допустимый expr
также можно понимать как указатель на функцию.
Этот код не компилируется:
int main()
{
int x(int());
return x + 3;
}
prog.cpp:4:11: error: invalid conversion from ‘int (*)(int (*)())’ to ‘int’ [-fpermissive]
return x + 3;
^
...
auto v { expr };
почти всегда неверен, потому что тип v становится initializer_list вместо T.
См. рекомендации по использованию auto: http://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/
Помимо случаев, когда значение отличается (например, vector<int> v(12)
не дает вам вектор со значением 12 в нем), компилятор должен дать вам то же самое для всех вышеперечисленных, и это действительно просто личное предпочтение, которое диктует, что "лучше".
auto
полезен, когда тип трудно печатать, и тип ясен из контекста. Но auto x = 12;
трудно сказать, подписана ли она или нет, например, [я не знаю правил, вероятно, подписанных].
Я думаю, не нужно использовать auto как
auto x = 12332; // or
auto z = 0xffff; //
Поскольку,
auto x = 12332; // type is 'int'
auto x2 = 0xffff // type is 'int'
auto y = 0xffffffff; // 8 fs, type is unsigned int
auto z = 0xfffffffff;// 9 fs, type is long long
auto t = 0xffffffffffffffff; // 16 fs, type is unsigned long long.
Но вы можете использовать
auto size = array.size();
Это довольно сложный вопрос.
Есть две разные проблемы.
Во-первых, следует ли использовать вычет типа или нет, то есть использовать спецификатор auto
или явно указать тип. В общем, я бы сказал, что лучше явно указать тип, который поможет с удобочитаемостью, за исключением того, что тип длинный и громоздкий (например, итераторы):
auto it = vec.begin();
или если тип очевидный из инициализатора:
auto pfoo = new Foo(x,y,z);
или если вам не нужна читаемость.
Во-вторых, какой тип инициализации использовать. Существует прямая инициализация, инициализация копирования и инициализация списка, а поведение инициализации сильно зависит от типа адресата. Различия между ними описаны в разделе 8.5 стандарта С++. Также инициализация появляется в большем количестве мест, чем просто простые объявления. Интериализация происходит при передаче параметров, возвратных значениях, подвыражениях, условиях оператора, границах массива и многих других местах. Это действительно то, что вам нужно понять, детали и краткое резюме не собираются сокращать его.