C++ 初始化表达式的每种方法的优缺点是什么?
这本书的灵感来自安德烈·亚历山德雷斯库(Andrei Alexandrescu)的作品 使用以下方法初始化表达式的利弊是什么?什么时候我应该选择一个而不是另一个C++ 初始化表达式的每种方法的优缺点是什么?,c++,c++11,c++14,C++,C++11,C++14,这本书的灵感来自安德烈·亚历山德雷斯库(Andrei Alexandrescu)的作品 使用以下方法初始化表达式的利弊是什么?什么时候我应该选择一个而不是另一个 auto v = expr; T v = expr; auto v(expr); T v(expr); auto v { expr }; T v {expr}; auto v=expr;tV=expr很好,但是在自动版本中,可能很难理解expr的类型 例如,在auto x=snafuscate()中,x的类型是什么 在存在歧义的情况
auto v = expr;
T v = expr;
auto v(expr);
T v(expr);
auto v { expr };
T v {expr};
auto v=expr;tV=expr
很好,但是在自动版本中,可能很难理解expr
的类型
例如,在auto x=snafuscate()中代码>,x的类型是什么
在存在歧义的情况下,最好将右侧的类型显式声明为:autox=Gadget{snafuscate()}代码>
autov(expr)编码>和tv(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;
^
autov{expr}代码>几乎总是错误的,因为v的类型变成了初始值设定项列表而不是T
有关自动的最佳实践,请参见:除了含义不同的情况(例如,vectorv(12)
不会给您一个值为12的向量),编译器应该为上述所有内容提供相同的内容,并且实际上只是个人偏好决定了哪个“更好”
auto
在类型难以键入且类型从上下文中清除时非常有用。但autox=12代码>很难区分它是有符号的还是无符号的,例如[我不知道规则,可能是有符号的] 我认为,不必使用自动作为
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 pfoo = new Foo(x,y,z);
或者如果你不关心可读性
第二个问题是使用什么类型的初始化。有直接初始化、复制初始化和列表初始化,而初始化的行为在很大程度上取决于目标的类型。在C++标准的第8.5节中描述了它们之间的差异。此外,除了简单的声明之外,初始化在更多的地方出现。初始化发生在参数传递、返回值、子表达式、语句条件、数组边界和许多其他地方。这确实是一件你需要了解细节的事情,一些简短的总结并不能减少它
auto v = expr;
auto v(expr);
当您在代码中不知道expr
的类型并希望保持通用性时,或者在代码中完全清楚expr
的类型(定义就在上面一行,等等),这样auto
就不会增加混淆
初始化的形式,不管是否是parens,都是不相关的(只与语言律师相关,因为存在细微的差异)。使用你觉得更舒服的东西
如果您的代码中不清楚什么是expr
(定义相距太远等),或者您不知道expr
的类型,但希望v
属于t
类型。如果要继续使用“expr”所具有的“值类型”(即expr
是字符串,而T
是字符串类型),请使用第一种形式。如果您建立了一种全新的值(即小部件
,并且expr
是小部件的颜色),请使用第二种形式
在当前的C++中(不在未来几年内)不要使用它。它将声明
v
为std::initializer\u列表
。如果您需要,请直接使用该类型并将其写出。这太微妙了(有人建议beyond-C++14来改变这一事实,所以希望您可以用C++17或类似的语言编写)
如果您想保护自己不受转换范围的限制(即从1000
意外地转换为char
),或者如果您想初始化具有初始值设定项列表构造函数的类,或者如果您有一个要初始化的成员的聚合,请使用此表单。或者,如果您处理的是初始值设定项列表构造函数、聚合或简单非类类型,则可以使用以下命令
T v = { expr };
我不会用它来调用任意构造函数。我会使用下面的表格
T v(expr);
然而,也有人更喜欢使用大括号形式。我想确定我的代码在做什么,因此当我想调用构造函数,而不想随机执行聚合或列表初始化构造函数调用时,我会使用括号而不是大括号。只要它更容易阅读。例如,auto p=std::make_shared(1,2,3)代码>。任何时候,描述性函数都会返回一些明显的难以键入的内容—迭代器、引用包装器、弱指针锁等。所有这些都取决于T
和expr
。例如,如果<代码> t>代码>是代码> int <代码>,我将不使用<代码> Auto < /Cord>。@ KrErkSB,但是一些C++ Grurs认为上面最丑陋的语法之一更为可取,具体地说是代码> AutoV{ExpR};代码>我想知道why@pyCthon:品味问题?问题当然是tx(U())
是一个函数声明,因此tx{expr}
是更安全的建议。同上,不需要隐式复制构造函数。我仍然认为它比“通常”的语法更难看。autov{expr}
几乎总是错误的;它提供了一个std::initializer\u列表
而不是T
auto x=12代码>为带符号整数
,自动x=12u代码>是无符号整数
@xlc:和自动y=123456789876
<代码>自动z=0x1234auto v { expr };
T v {expr};
T v = { expr };
T v(expr);