C++中的语义差异:定义常量数据实例

3

在C++11中,对于初始化int类型的常量数据成员,以下四种不同的语法是否具有相同的效果?如果不是,它们之间有什么区别?

{
    const int a = 5; //usual initialization, "=" is not assignment operator here it is an initialization operator.
}
{
    const int a(5); //calling the constructor function directly
}
{
    const int a = {5}; //similar to initializing an array
}
{
    const int a{5}; //it should work, but visual studio does not recognizing it
}

为什么第四个语句在Visual Studio中无法被识别为有效语句?

好的,我正在使用Visual Studio 2012,并遇到以下错误:'1- 错误C2734:如果不是extern,则必须初始化const对象'a'' '2- 错误C2601:本地函数定义是非法的' '3- 此行包含尚未匹配的'{' - A_Matar
4个回答

7

它们都是有效的,在Visual Studio 2013中相同(如@remyabel所建议,最后一个在VS2012中无效)。

两个{...}语法可以根据类型调用不同的构造函数,但类型int 不使用构造函数

当构造接受std :: initializer_list 的类时,它们将有所不同

例如,考虑一下始终是std :: vector的一部分的这个构造函数:

explicit vector( size_type count ... );

这是C++11新增的一个特性

vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );

这里,vector<int>(5)将调用第一个构造函数并创建一个大小为5的向量。
vector<int>{5}将调用第二个构造函数,并创建一个含有单个5的向量。

“for any int” 是什么意思?这个语法只适用于 int 吗? - A_Matar
但是 int 有一个构造函数,你可以使用 int() 调用它,并且它被定义为创建一个零初始化标量。另外作为一种练习,new int() 总是创建一个新的零整数,但是 new int 则创建一个未初始化的整数。 - v.oddou
2
@v.oddou 初始化规则适用于不同类型的对象,包括类类型。int 不是一个类类型。 - user3920237

4
在C++03中这些是等价的。
const int a = 3;
const int a(3);

在C++11中引入了统一的初始化语法,因此:
const int a{3};
const int a = {3};

允许使用(){},并且它们是等效的。然而,在某些情况下,前两者和后两者并不等效。{}不允许缩小范围。例如:

int abc = {12.3f};
int xyz(12.3f);

这是GCC的说法。

error: type 'float' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]

int abc = {12.3f};
           ^~~~~

warning: implicit conversion from 'float' to 'int' changes value from 12.3 to 12 [-Wliteral-conversion]

int abc = {12.3f};
          ~^~~~~

前者导致错误,而后者只是警告。

Caveats 在初始化语法中的使用:如果a是一个接受std::initializer_list类型的对象,则const MyClass a = { 1 }表示您正在使用该构造函数,而不是单个int参数的构造函数,即使该构造函数是可用的(在Drew的回答中解释);如果你想选择另一个构造函数,那么你必须使用()语法。如果a是一个数组,则您正在使用聚合初始化。

在这里查看C++中可用的各种初始化选项。


1

Visual Studio 2012 不支持这种语法,但在VS2013中已实现。在VS2012选项卡中,initializers的文档没有描述使用花括号(又称为 direct-list-initialization)进行直接初始化的任何方式。以下是MSVC关于有效初始化程序语法的文档,它不一定反映了从语言专家的角度来看什么是有效的。

声明符可以为对象指定初始值。唯一为const类型对象指定值的方法是在声明符中。指定此初始值的声明符部分称为初始化器。有两种基本类型的初始化器:
使用等号语法调用的初始化器,包括聚合初始化器: = expression = {expression-list} = {{expression-list}, {expression-list}, ...}
使用函数样式语法调用的初始化器: (expression)

0

编码风格是非常主观的,从中获得实质性的性能优势的可能性极小。但是,以下是我认为您可以从广泛使用统一初始化中获得的收益:

所有4个语句都是有效的,并且它们是相同的。

const int a = 5; -> 无论如何,这是正常的初始化语法。 不需要解释!

const int a(5); -> 函数类型初始化

const int a = {5}; -> 数组类型初始化

const int a{5}; -> 在Visual Studio 2012中不允许,但在Visual Studio 2013中已添加了初始化器列表支持。因此,const int a{5}在VS2013中可以编译而没有任何问题。

但是,
您放弃的唯一真正的力量是缩小。您不能使用统一初始化将较小的值初始化为较大的值。

int val{5.5};

那段代码无法编译。你可以使用老式的初始化方法,但不能使用统一初始化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接