C++中的语义差异,定义常量数据实例
Semantic difference in C++, defining a constant data instance
在 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 2013 中都有效且相同(最后一个在 VS2012 中无效,正如@remyabel 建议的那样)。
这两个 {...}
语法在为类型调用构造函数方面可能与其他语法不同,但是类型 int
不使用构造函数。
在构建接受 std::initializer_list<T>
.
的 class 时,它们将 不同
举个例子,这个构造函数以某种形式一直是 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
的矢量。
在 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};
~^~~~~
所以前者产生了一个错误,而后者只是一个警告。
统一初始化语法中的注意事项:如果a
是一个接受std::initializer_list
类型的对象,那么const MyClass a = { 1 }
就意味着你'正在使用该构造函数而不是构造函数采用单个 int
即使它可用(在 Drew 的答案中解释);如果您想选择其他构造函数,则必须使用 ()
语法。如果 a
是一个数组,那么您正在使用聚合初始化。
See here 用于 C++ 中可用的各种初始化选项。
Visual Studio 2012 doesn't support this syntax. It is however implemented in VS2013. The documentation for initializers in the VS2012 tab doesn't describe any way of using direct initialization with braces (aka,direct-list-initialization
)。以下是 MSVC 关于有效初始化语法的文档,从语言律师的角度来看,它不一定反映什么是有效的。
Declarators can specify the initial value for objects. The only way to
specify a value for objects of const type is in the declarator. The
part of the declarator that specifies this initial value is called the
initializer. There are two fundamental types of initializers:
- Initializers invoked using the equal-sign syntax, including aggregate initializers:
= expression
= { expression-list }
= { { expression-list}, {expression-list}, . . . }
- Initializers invoked using function-style syntax:
( expression )
编码风格最终是主观的,并且不太可能从中获得实质性的性能优势。但我要说的是,您可以从自由使用统一初始化中获益:
所有 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};
那将无法编译。您可以使用老式初始化来做到这一点,但不能使用统一初始化。
在 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 2013 中都有效且相同(最后一个在 VS2012 中无效,正如@remyabel 建议的那样)。
这两个 {...}
语法在为类型调用构造函数方面可能与其他语法不同,但是类型 int
不使用构造函数。
在构建接受 std::initializer_list<T>
.
举个例子,这个构造函数以某种形式一直是 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
的矢量。
在 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}; ~^~~~~
所以前者产生了一个错误,而后者只是一个警告。
统一初始化语法中的注意事项:如果a
是一个接受std::initializer_list
类型的对象,那么const MyClass a = { 1 }
就意味着你'正在使用该构造函数而不是构造函数采用单个 int
即使它可用(在 Drew 的答案中解释);如果您想选择其他构造函数,则必须使用 ()
语法。如果 a
是一个数组,那么您正在使用聚合初始化。
See here 用于 C++ 中可用的各种初始化选项。
Visual Studio 2012 doesn't support this syntax. It is however implemented in VS2013. The documentation for initializers in the VS2012 tab doesn't describe any way of using direct initialization with braces (aka,direct-list-initialization
)。以下是 MSVC 关于有效初始化语法的文档,从语言律师的角度来看,它不一定反映什么是有效的。
Declarators can specify the initial value for objects. The only way to specify a value for objects of const type is in the declarator. The part of the declarator that specifies this initial value is called the initializer. There are two fundamental types of initializers:
- Initializers invoked using the equal-sign syntax, including aggregate initializers:
= expression = { expression-list } = { { expression-list}, {expression-list}, . . . }
- Initializers invoked using function-style syntax:
( expression )
编码风格最终是主观的,并且不太可能从中获得实质性的性能优势。但我要说的是,您可以从自由使用统一初始化中获益:
所有 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};
那将无法编译。您可以使用老式初始化来做到这一点,但不能使用统一初始化。