我在标准C ++库中观察到以下向量构造函数
explicit vector(size_type n);
vector(size_type n, const T& value, const Allocator& = Allocator());
为什么第二个构造函数没有标记为explicit
?这编译,让我感觉不好
void f(vector<string>);
int main() {
f({10, "foo"});
}
如果我省略"foo"
,它就不会编译,这就是我将int和字符串的一对(复合)值传递给想要一个字符串向量的函数时的预期。
答案 0 :(得分:3)
我想知道在创建临时文件时,{ ... }
始终表示容器元素列表是否合法。这似乎是你的假设。 IMO单参数构造函数需要被声明为explicit
以避免未经考虑的转换序列或无意义的分配,例如:
vector<int> x = 3;
另一方面,对于双参数版本,唯一方式这个构造函数可以在创建临时函数时使用花括号调用,并且程序员很清楚他在那里放什么例如,我很清楚10
和"hello"
并不代表容器元素列表,因为10
不是字符串。
如果我真的想传递一个初始化为"hello"
的10个元素的向量,我会因为必须编写f(vector(10, "hello"))
而不是仅仅f({10, "hello"})
而烦恼。
所以总结一下:虽然单参数构造函数需要声明为explicit
,但我认为这对于双参数值并不是强制性的,因为不是一对花括号中的所有内容应该被解释为容器元素列表。
答案 1 :(得分:1)
如果我省略“foo”,它就不会编译,这就是我的期望 当我将int和string的一对(复合)值传递给想要的函数时 一串字符串。
不,你没有传递一对int和一个字符串,但你创建了一个大小为10的向量,其内容为字符串,如“foo”。它没有错!我可以想象一下,从一开始就创建一个包含相等字符串的向量可能是有用的。
答案 2 :(得分:0)
当我将int和string的一对(复合)值传递给想要一个字符串向量的函数时,这就是我所期望的。
嗯,这是你的问题。
{...}
不是“复合值”。它不是一个清单。它说,“使用这些值初始化对象”。如果有问题的对象是聚合,它将使用聚合初始化。如果有问题的对象是非聚合类型,它将根据类型的匹配构造函数和C ++ 11中braced-init-lists的各种规则选择要调用的构造函数。
您不应将{10, "foo"}
视为两个值的列表。它是一个初始化程序,包含两个值。它可以与std::pair<int, const char *>
一起使用,等等。
std::vector
的构造函数不明确的原因恰恰是允许这个构造。单参数构造函数是显式的,否则隐式转换规则将允许这样:
std::vector<T> v = 5; //???
或者,更重要的是:
void Foo(const std::vector<T> &v);
Foo(5); //???
我们不希望整数可以隐式转换为std::vector
s。但是,当您使用初始化程序时,允许更广泛的“隐式”转换更为合理,因为您可以在那里看到{}
语法。
使用单参数情况,不清楚用户的含义。使用{}语法, 清除用户的含义:初始化对象。
Foo({10, "foo"}); //Initializes the first argument given the values.