隐式构造函数转换仅适用于显式vector :: vector

时间:2009-12-21 23:11:04

标签: c++ constructor type-conversion

我喜欢将二维数组初始化为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.

前两个例子是否因某种原因符合规定?为什么我可以转换4050而不转换2


结语:请参阅http://gcc.gnu.org/onlinedocs/libstdc++/ext/lwg-defects.html#438了解大多数编译器允许这样做的原因,但标准正在转向另一种方式。

4 个答案:

答案 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阻止它转换40std::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)下无效。