这是来自Andrei Alexandrescu的一篇文章的启发。
使用以下方法初始化表达式的优缺点是什么?我什么时候应该更喜欢其中一个?
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
就不会增加混淆。
初始化的形式,无论是否是括号,都无关紧要(仅与语言律师有关,因为存在细微差别)。使用你觉得更舒服的东西。
T v = expr;
T v(expr);
如果在您的代码中不清楚是什么expr
(定义相距太远等),或者如果您不知道类型expr
但想v
成为类型T
。如果您想继续使用“expr”具有的“值类型”(即 ifexpr
是字符串并且T
属于字符串类型),请使用第一种形式。如果您建立了一种全新的值(即 a Widget
,并且expr
是小部件的颜色),请使用第二种形式。
auto v { expr };
永远不要在当前的 C++ 中使用它(可能在未来几年内)。它将声明v
为std::initializer_list<TypeOfExpr>
. 如果需要,请直接使用类型并将其写出来。它太微妙了(并且有提议超越 C++14 来改变这个事实,所以希望你可以用 C++17 或类似的东西来编写它)。
T v {expr};
如果您想保护自己免受缩小转换(即从意外1000
到char
意外),或者如果您想初始化一个具有初始化列表构造函数的类,或者如果您有一个要初始化的成员的聚合,使用这个表格。或者,如果您正在处理初始化列表构造函数、聚合或简单的非类类型,则可以使用以下内容
T v = { expr };
我不会用它来调用任意构造函数。我会使用以下表格
T v(expr);
但是,有些人也更喜欢使用大括号形式。我想确定我的代码在做什么,因此当我想调用构造函数并且不想随机执行聚合或列表初始化构造函数调用时,我使用括号而不是大括号。
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。
有关汽车的最佳实践,请参阅: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);
或者如果您不关心可读性。
第二个是使用什么类型的初始化。有直接初始化、复制初始化和列表初始化——初始化的行为很大程度上取决于目标的类型。C++ 标准的第 8.5 节描述了它们之间的区别。此外,初始化出现在更多地方,而不仅仅是简单的声明。初始化发生在参数传递、返回值、子表达式、语句条件、数组边界和许多其他地方。这确实是你需要了解细节的东西,一些简短的总结并不会削减它。