简述
这个问题不仅限于std::vector
,而是源于以下规则(来自标准引用)。
让我们逐个案例看看发生了什么,以及为什么在使用lvalue
时会出现所述的缩小转换错误/警告。
案例1
这里我们考虑:
int lvalue = 6; // lvalue is not a constant expression
//
std::vector<int*> myvector { 6 };
std::vector<int*> myvector{ lvalue };
//
请注意,
std::vector<int*>
没有接受
int
初始化列表的初始化器列表构造函数。
因此,在这种情况下,将使用size_t count
构造函数。现在让我们看看出现缩小转换错误/警告的原因。
当使用名为lvalue
的变量时会产生错误/警告,但是使用prvalue int
时不会产生错误/警告的原因是,在前一种情况下,lvalue
不是常量表达式,因此我们有一个缩小转换。这可以从dcl.init.list#7中得到证明:
缩小转换是隐式转换
- 从整数类型或未作用域枚举类型到不能表示原始类型所有值的整数类型的转换,除非源是一个整数提升后可以适应目标类型的常量表达式。
(强调我的)
这意味着从类型为int
的表达式lvalue
(它是一个左值表达式)到向量的std::vector::vector(size_t, /*other parameters*/)
构造函数的size_t
参数的转换是一个缩小转换。但是,从prvalue int 6
到向量的std::vector::vector(size_t, /*other parameters*/)
的size_t
参数的转换不是缩小转换。
为了证明这确实是这种情况,请看一些例子:
例1
int main()
{
std::size_t a{1};
int i = 1;
std::size_t b{i};
constexpr int j = 1;
std::size_t c{j};
return 0;
}
示例2
struct Custom
{
Custom(std::size_t)
{
}
};
int main()
{
Custom c{3};
int i = 3;
Custom d{i};
constexpr int j = 3;
Custom e{j};
return 0;
}
演示
案例2
在这里我们考虑:
//
std::vector<int> myvector{num_elements};//this uses constructor initializer list ctor
在这种情况下,对于
std::vector<int>
,有一个初始化列表构造函数可用,由于我们在这里使用了大括号
{}
而不是小括号
()
,因此它将优先于
size_t count
构造函数。因此,将创建一个大小为
1
的向量。更多详细信息请参见
使用大括号初始化列表时为什么首选std::initializer_list构造函数?。
另一方面,当我们使用:
std::vector<int> myvector(num_elements); //this uses size_t ctor
在这种情况下,std::vector
的size_t
构造函数将被用作初始化列表构造函数甚至不可行的情况,因为我们使用了括号()
。因此,将创建一个大小为6
的向量。您可以使用下面给出的示例进行确认:
struct Custom
{
Custom(std::size_t)
{
std::cout<<"size t"<<std::endl;
}
Custom(std::initializer_list<int>)
{
std::cout<<"initializer_list ctor"<<std::endl;
}
};
int main()
{
Custom c(3);
return 0;
}
std::vector<int> myvector{num_elements};
创建一个只有一个元素的向量。这是正确的,因为std::vector<int>
不同于std::vector<int*>
。(它有一个接受整数初始化列表的构造函数,而std::vector<int*>
没有。) - Nathan Pierson