代码之家  ›  专栏  ›  技术社区  ›  Potatoswatter

隐式构造函数转换只能在显式vector::vector上工作,有时

  •  2
  • Potatoswatter  · 技术社区  · 15 年前

    我喜欢将二维数组初始化为 vector<vector<int> >(x,y) . x 传递给 vector<vector<int> > 的构造函数和 y 传递给 vector<int> 的构造函数, X 时代。虽然这似乎是被C++ 03禁止的,因为构造函数是 explicit 它总是有效的,即使在科莫。我也可以打电话 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 为什么大多数编译器都允许这样做,但标准却在改变。

    4 回复  |  直到 15 年前
        1
  •  5
  •   AnT stands with Russia    15 年前

    你关于Comeau的假设暗示 explicit 构造函数很可能不正确。这种行为的确是失败的,但问题是不同的。

    我怀疑这是Comeau附带的标准库实现中的一个bug,而不是核心Comeau编译器本身(尽管在本例中这一行比较模糊)。

    如果构建的快速虚拟类的构造函数属性类似于 std::vector 尝试同样的方法,您会发现编译器正确地拒绝执行构造。

    它之所以接受您的代码,最有可能的原因是因为 STD::载体 . 它可以解释为 (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());
    

    标准库规范明确指出,当两个整数值用作参数时,实现必须确保以某种方式选择了所形成的构造函数,即。 (尺寸,初始值) . 怎么做-没关系。它可以在库级别完成,也可以在核心编译器中进行硬编码。它可以用任何其他方式来完成。

    但是,作为对 ( 20, 40 ) 参数Comeau编译器似乎错误地选择和实例化后一个构造函数 InputIterator = int . 我不知道它是如何编译构造函数的专门版本的,因为整数值不能也不会作为迭代器工作。

    如果你试试这个

    vector< vector< int > > v( 20U, 40 ); 
    

    您将发现编译器现在报告了一个错误(因为它不能再使用构造函数的两个迭代器版本),并且 明确的 在第一个构造函数上阻止它转换 40 到A STD::载体 .

    同样的事情也发生在 assign . 这当然是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)  
    

    如果输入器是整数类型

    我怀疑如果上面的内容是逐字解释的,编译器就可以假定 static_cast 是暗示存在的(嗯…也就是说),因为同样的原因,这个代码是合法的 static_cast< std::vector<int> >(10) 是合法的,尽管相应的构造函数 明确的 . 存在 静态铸造 是什么使得编译器可以使用 明确的 构造函数。

    如果comeau编译器的行为是正确的(我怀疑它实际上是正确的,根据标准的要求),我想知道这是否是委员会的意图,让这样一个漏洞保持开放,并允许实现在 明确的 向量元素的构造函数可能存在限制。

        2
  •  1
  •   Drew Dormann    15 年前

    前两个例子是否出于某种原因实际符合?

    它们不符合我刚尝试的编译器。(GCC 4.4.1)

    为什么我可以转换40和50而不是2?

    由于前两行与标准不一致,只有COMEAU才可能知道它们不一致的原因。

    标准要求从int类型到任意向量的显式转换不是偶然的。这样做是为了防止混淆代码。

        3
  •  1
  •   leiz    15 年前

    vector< vector< int > > v( 20, 40 ); 使用您可能不熟悉的构造函数。这里调用的构造函数是 vector(iterator start, iterator end);

    在内部,它专门用于int迭代器,因此第一个参数被视为count,第二个参数是初始化向量的值。因为在将第二个参数赋给向量值时有一个强制转换,所以内部的构造函数 vector<T>(int, const T&) 将以值40调用。因此,内部向量用40 0 s构造。

        4
  •  0
  •   rafak    15 年前

    您的示例不符合要求。如您所说,构造函数是显式的,因此不允许为构造函数传递int(y)而不是向量(并且y不向向量构造函数传递“x次”:第二个参数只创建一次,以初始化插入的对象)。 您的示例不适用于GCC(4.4&4.5)。