考虑以下演示程序。
#include <iostream>
struct A
{
int x;
explicit A( int x = 0 ) : x( x ) {}
};
int main()
{
A a1 { 10 };
std::cout << "a1.x = " << a1.x << '\n';
}
在这个声明中
A a1 { 10 };
这里使用了直接初始化。
而在注释的声明中
// A a2 = { 10 };
这可以被重写为:
也可以被重写为
// A a2 = 10
这里使用了复制初始化。但是构造函数的声明带有explicit
关键字。因此,编译器会报错。这意味着无法将整数对象10
隐式转换为类型A
。
你可以改为如下写法:
A a2 = A{ 10 };
这是显式调用构造函数。
当然,对于基本类型来说没有区别,因为除了使用花括号初始化时不允许缩小转换之外,两个构造函数都不会被应用,例如:
int x { 1.0 };
当类型说明符为占位符
auto
时,存在很大的差异。
例如:
auto x = 10;
x
的类型为int
。
auto x { 10 };
x
再次具有类型 int
。
auto x = { 10 };
现在,
x
的类型是
std::initializer_list<int>
。
例如,您可以重写循环。
for (unsigned int counter{ 1 }; counter <= 20; ++counter) {
下面方式。
for ( auto counter{ 1u }; counter <= 20; ++counter) {
但是你可能不允许写。
for ( auto counter = { 1u }; counter <= 20; ++counter) {
因为在这种情况下,变量counter
的类型是std::initializer_list<unsigned int>
。
因此,一般有以下形式的初始化:
T x = value;
T x = { value };
T x( value );
T x { value };
例如
#include <iostream>
int main()
{
int x1 = 1;
std::cout << "x1 = " << x1 << '\n';
int x2 = ( 2 );
std::cout << "x2 = " << x2 << '\n';
int x3( 3 );
std::cout << "x3 = " << x3 << '\n';
int x4{ 4 };
std::cout << "x4 = " << x4 << '\n';
}
程序输出为:
x1 = 1
x2 = 2
x3 = 3
x4 = 4
但是,当使用模板函数时,有一种情况需要使用
T{}
作为初始化器,而不是
T()
。
考虑以下示例程序。
#include <iostream>
template <class>
void f()
{
std::cout << "f<T>() is called\n";
}
template <int>
void f()
{
std::cout << "f<int>() is called\n";
}
int main()
{
f<int()>();
f<int{}>();
}
它的输出是:
f<T>() is called
f<int>() is called
int()
作为模板参数指定了类型模板参数 int
,而 int{}
作为模板参数则指定了一个类型为 int
、值为 0
的非类型模板参数。