Nic*_*ick 6 c++ variables for-loop initialization list-initialization
我是C ++编程的新手。我在Google的任何地方都找不到我的答案,因此希望可以在这里回答。
以下之间有区别吗
unsigned int counter{ 1 };
Run Code Online (Sandbox Code Playgroud)
要么
unsigned int counter = 1;
Run Code Online (Sandbox Code Playgroud)
这本书使用了第一种选择,它使我感到困惑,因为它没有解释差异。以下是我正在关注的书中的以下代码。
#include <iostream>
#include <iomanip>
#include <cstdlib> // contains function prototype for rand()
using namespace std;
int main()
{
for (unsigned int counter{ 1 }; counter <= 20; ++counter) {
cout << setw(10) << (1 + rand() % 6);
// if counter is divisible by 5, start a new line of output
if (counter % 5 == 0) {
cout << endl;
}
}
}
Run Code Online (Sandbox Code Playgroud)
是的,它们是C ++中的两种不同类型的初始化。
有关所有详细信息,您可以直接参考文档。
但是,我可以强调:
复制初始化比直接初始化要宽松:显式构造函数不会转换构造函数,因此不会考虑进行复制初始化。
对于unsigned int类型(例如您的情况),两个初始化之间没有真正的区别。
注意
第一个语句(unsigned int counter{ 1 })中花括号的使用提供了附加的约束:
否则(如果T不是类类型),如果braced-init-list仅具有一个元素[...],则T被直接初始化,除非不允许缩小转换。
换句话说,在初始化中使用花括号不允许出现数据松动。
那是:
unsigned int counter{ 12.3 }; // error!!!
Run Code Online (Sandbox Code Playgroud)
无法编译,因为您尝试使用浮点值初始化整数。
请注意,这是初始化中花括号的“属性”。它与初始化类型不严格相关。
实际上,您还可以编写:
unsigned int counter = { 12.3 }; // error!
Run Code Online (Sandbox Code Playgroud)
相反,它是一个副本初始化,但使用花括号不允许缩小转换范围。
考虑以下演示程序。
#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 a2 = { 10 };
}
Run Code Online (Sandbox Code Playgroud)
在这份声明中
A a1 { 10 };
Run Code Online (Sandbox Code Playgroud)
这里使用的是直接初始化。
并在评论声明中
// A a2 = { 10 };
Run Code Online (Sandbox Code Playgroud)
也可以重写为
// A a2 = 10;
Run Code Online (Sandbox Code Playgroud)
这里使用了复制初始化。但构造函数是用说明符声明的explicit。所以编译器会报错。也就是说它无法将整数对象隐式转换10为类型A。
你可以写
A a2 = A{ 10 };
Run Code Online (Sandbox Code Playgroud)
那就是显式调用构造函数。
当然,对于基本类型没有区别,因为除了使用大括号初始化时不允许缩小转换之外,都没有应用构造函数,例如
int x { 1.0 };
Run Code Online (Sandbox Code Playgroud)
当类型说明符是占位符时,有很大的区别auto。
例如
auto x = 10;
Run Code Online (Sandbox Code Playgroud)
x有类型int.
auto x { 10 };
Run Code Online (Sandbox Code Playgroud)
x又有型int。
auto x = { 10 };
Run Code Online (Sandbox Code Playgroud)
现在x有类型std::initializer_list<int>。
例如你可以重写你的循环
for (unsigned int counter{ 1 }; counter <= 20; ++counter) {
Run Code Online (Sandbox Code Playgroud)
以下方式
for ( auto counter{ 1u }; counter <= 20; ++counter) {
Run Code Online (Sandbox Code Playgroud)
但你可能不会写
for ( auto counter = { 1u }; counter <= 20; ++counter) {
Run Code Online (Sandbox Code Playgroud)
因为在这种情况下变量的类型counter是std::initializer_list<unsigned int>.
所以一般来说你有以下形式的初始化
T x = value;
T x = { value };
T x( value );
T x { value };
Run Code Online (Sandbox Code Playgroud)
例如
#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';
}
Run Code Online (Sandbox Code Playgroud)
程序输出是
x1 = 1
x2 = 2
x3 = 3
x4 = 4
Run Code Online (Sandbox Code Playgroud)
但还有一种情况,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{}>();
}
Run Code Online (Sandbox Code Playgroud)
它的输出是
f<T>() is called
f<int>() is called
Run Code Online (Sandbox Code Playgroud)
int()用作模板参数的构造指定类型模板参数,int而用作模板参数指定的构造则指定类型等于int{}的非类型模板参数。int0