我喜欢将二维数组初始化为vector<vector<int> >(x,y)
。 x
传递给vector<vector<int> >
的构造函数,y
传递给vector<int>
的构造函数x
次。虽然这似乎被C ++ 03禁止,因为构造函数是explicit
,它总是有效,即使在Comeau上也是如此。我也可以这样打电话给vector::assign
。但是,出于某种原因,不是vector::push_back
。
vector< vector< int > > v( 20, 40 ); // OK: convert 40 to const T&
v.assign( 30, 50 ); // OK
v.push_back( 2 ); // error: no conversion, no matching function, etc.
前两个例子是否因某种原因符合规定?为什么我可以转换40
和50
而不转换2
?
结语:请参阅http://gcc.gnu.org/onlinedocs/libstdc++/ext/lwg-defects.html#438了解大多数编译器允许这样做的原因,但标准正在转向另一种方式。
答案 0 :(得分:5)
您对Comeau隐式调用explicit
构造函数的假设很可能是错误的。行为确实被打破了,但问题是不同的。
我怀疑这是Comeau附带的标准库实现中的一个错误,而不是核心Comeau编译器本身(尽管在这种情况下线条模糊)。
如果你构建一个具有类似于std::vector
的构造函数属性的快速虚拟类并尝试相同的东西,你会发现编译器正确地拒绝执行构造。
它接受你的代码的最可能原因是std::vector
的双参数构造函数的众所周知的形式歧义。它可以解释为(size, initial value)
构造函数
explicit vector(size_type n, const T& value = T(),
const Allocator& = Allocator());
或(begin, end)
模板构造函数,后者接受两个迭代器
template <class InputIterator>
vector(InputIterator first, InputIterator last,
const Allocator& = Allocator());
标准库规范明确指出,当两个整数值用作参数时,实现必须确保选择形成的构造函数,即(size, initial value)
。怎么做 - 没关系。它可以在库级别完成,可以在核心编译器中进行硬编码。它可以通过任何其他方式完成。
但是,为响应( 20, 40 )
参数,Comeau编译器似乎错误地选择并使用InputIterator = int
实例化后一个构造函数。我不知道它如何设法编译构造函数的专用版本,因为整数值不能也不会作为迭代器。
如果你试试这个
vector< vector< int > > v( 20U, 40 );
您会发现编译器现在报告错误(因为它不能再使用构造函数的双迭代器版本),并且第一个构造函数上的explicit
阻止它转换40
到std::vector
。
同样的事情发生在assign
上。这当然是Comeau实现的一个缺陷,但是,再一次,实验表明,很可能所需的行为应该在库级强制执行(核心编译器似乎工作正常),并且不知何故它完成得不正确。
在第二个想法中,我看到我的解释中的主要想法是正确的,但细节是错误的。另外,我认为在Comeau中将其称为问题可能是错误的。 Comeau可能就在这里。
标准在23.1.1 / 9中说
构造函数
template <class InputIterator>
X(InputIterator f, InputIterator l, const Allocator& a = Allocator())
具有与以下相同的效果:
X(static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l),
a)
如果InputIterator是整数类型
我怀疑如果按字面意思解释上述内容,则允许编译器假定在那里隐含了显式的static_cast
(好吧......),并且代码是合法的,原因相同{ {1}}是合法的,尽管相应的构造函数是static_cast< std::vector<int> >(10)
。 explicit
的存在使编译器可以使用static_cast
构造函数。
如果Comeau编译器的行为是正确的(并且我怀疑它实际上是正确的,正如标准所要求的那样),我想知道这是否是委员会的意图让这样的漏洞开放,并允许实现工作会导致可能存在于vector元素构造函数上的explicit
限制。
答案 1 :(得分:1)
出于某种原因,前两个示例是否真正符合要求?
他们对我刚试过的编译器不兼容。 (gcc 4.4.1)
为什么我可以转换40和50而不是2?
由于前两行与标准不一致,因此只有Comeau可能知道为什么它们的不一致性不一致。
标准要求从int类型到任意向量的显式转换并非偶然。这样做是为了防止令人困惑的代码。
答案 2 :(得分:1)
vector< vector< int > > v( 20, 40 );
使用您可能不熟悉的构造函数。这里调用的构造函数是vector(iterator start, iterator end);
在内部,它专门用于int迭代器,因此第一个参数被视为count,第二个参数是初始化向量的值。因为在将第二个参数赋值给向量值时存在强制转换,所以内部vector<T>(int, const T&)
的构造函数将以值40调用。因此,内部向量用40 0构造。
答案 3 :(得分:0)
您的示例不符合要求。正如你所说的那样,构造函数是显式的,所以不允许传递一个int(y)而不是构造函数的向量(并且y不会传递“x次”到向量构造函数:第二个参数只创建一次,以初始化插入的对象)。 您的示例在gcc(4.4&amp; 4.5)下无效。