我遇到了一件我认为很奇怪的事情:
#include <vector>
int numqueues = 1;
std::vector<float> priorities{numqueues, 1.f };
//^^^ warning: narrowing conversion of numqueues from int to float
//std::vector<float> priorities(numqueues, 1.f );
//^^^ No warning or error. And it's not because it's parsed as a function declaration
// as I can call push_back in main.
int main()
{
priorities.push_back(1);// No narrowing conversion needed
}
我已经使用几个编译器尝试过,但无法编译。
编辑:据说初始化器列表优先,看起来确实如此,但我试图模仿 std::vector 并且在这个例子中我没有得到缩小转换错误:
#include <vector>
#include <iostream>
#include <initializer_list>
template <typename T>
class MyVector
{public:
MyVector(size_t s, float f) {
std::cout << "Called constructor\n";
}
MyVector(std::initializer_list<T> init)
{
std::cout << "Called initializer list constructor\n";
}
};
int main()
{
MyVector<float> foo{ size_t(3), 2.f };
}
我做了完全相同的事情,用 size_t 和 float 初始化它,就像在另一个示例中一样,这个编译得很好。
在此声明中
std::vector<float> priorities{numqueues, 1.f };
编译器使用初始化列表构造函数。
vector(initializer_list<T>, const Allocator& = Allocator());
禁止初始化列表的缩小转换。
在此声明中
std::vector<float> priorities(numqueues, 1.f );
编译器使用指定元素数量及其初始值设定项的构造函数。
vector(size_type n, const T& value, const Allocator& = Allocator());
来自 C++ 14 标准(8.5.4 列表初始化)
2 如果构造函数的第一个构造函数是初始化列表构造函数 参数的类型为 std::initializer_list 或可能的引用 对于某些类型 E,cv 限定的 std::initializer_list ,以及 没有其他参数或者所有其他参数都有 默认参数(8.3.6)。 [ 注意:初始化列表构造函数是 在列表初始化中比其他构造函数更受青睐
和(13.3.1.7 通过列表初始化进行初始化)
1 当非聚合类类型 T 的对象被列表初始化时,例如 8.5.4 指定重载决策是根据 根据本节中的规则,重载决策选择 分两个阶段的构造函数:
(1.1) — 最初,候选函数是初始化列表 类 T 的构造函数 (8.5.4) 和参数列表包括 初始化列表作为单个参数。
(1.2) — 如果没有找到可行的初始化列表构造函数,则重载 再次进行解析,其中候选函数全部为 类 T 的构造函数和参数列表由以下组成 初始化列表的元素。
这是一个演示程序
#include <iostream>
#include <initializer_list>
struct A
{
A( std::initializer_list<float> )
{
std::cout << "A( std::initializer_list<float> )\n";
}
A( size_t, float )
{
std::cout << "A( size_t, float )\n";
}
};
int main()
{
A a1 { 1, 1.0f };
A a2( 1, 1.0f );
return 0;
}
程序输出为
A( std::initializer_list<float> )
A( size_t, float )
至于你附加的问题(8.5.4列表初始化)
7 缩小转换是隐式转换
(7.3) — 从整数类型或无作用域枚举类型到 浮点类型,除非源是常量 表达式和转换后的实际值将适合 目标类型,转换回时将产生原始值 原始类型,或
所以在这个列表中初始化
MyVector<float> foo{ size_t(3), 2.f };
使用适合 float 类型的常量表达式
size_t( 3 )
。
例如,如果在上面的演示程序中您将编写
size_t n = 1;
A a1{ n, 1.0f };
然后编译器应该发出有关缩小转换的消息(至少 MS VS 2019 C++ 编译器发出这样的错误消息)。
来自列表初始化的cppreference。
列表初始化通过以下方式限制允许的隐式转换 禁止以下行为:
...
从整数类型到浮点类型的转换,除非源是可以存储其值的常量表达式 完全符合目标类型
通常,列表初始化不会为您执行隐式转换。另外,因为
std::vector
有一个构造函数 vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );
,所以它是被调用来构造 vector
的构造函数。