从int到向量的隐式转换?

时间:2022-08-24 21:21:03

vector<T> has a constructor that takes the size of the vector, and as far as I know it is explicit, which can be proved by the fact that the following code fails to compile

向量 有一个构造函数,它取向量的大小,据我所知它是显式的,这可以通过以下代码无法编译的事实来证明

void f(std::vector<int> v);
int main()
{
    f(5);
}

What I cannot understand and am asking you to explain is why the following code compiles

我不能理解并要求您解释的是为什么要编译下面的代码

std::vector<std::vector<int>> graph(5, 5);

Not only does it compile, it actually resizes graph to 5 and sets each element to a vector of five zeros, i.e. does the same as would the code I would normally write:

它不仅编译,它实际上还将图形大小调整为5,并将每个元素设置为一个5个0的向量,即与我通常编写的代码相同:

std::vector<std::vector<int>> graph(5, std::vector<int>(5));

How? Why?

如何?为什么?

Compiler: MSVC10.0

编译器:MSVC10.0


OK, seems it's an MSVC bug (yet another one). If someone can elaborate on the bug in an answer (i.e. summarize the cases where it is reproduced) I would gladly accept it

好吧,看来这是MSVC的漏洞(又一个)。如果有人能在回答中详细阐述这个错误(例如,总结出它被复制的案例),我很乐意接受。

4 个解决方案

#1


7  

It is not really a bug. The question is what could go wrong to allow the second piece of code while the first does not compile?

它不是真正的bug。问题是,当第一部分不编译时,允许第二部分代码出现错误的地方是什么?

The issue is that while it seems obvious to you what constructor you want to call when you do:

问题是,当你这么做的时候,你想调用什么构造函数是显而易见的:

std::vector<std::vector<int>> graph(5, 5);

it is not so clear for the compiler. In particular there are two constructor overloads that can potentially accept the arguments:

对编译器来说不是很清楚。特别是有两个构造函数重载可以接受参数:

vector(size_type,const T& value = T());

template <typename InputIterator>
vector(InputIterator first, InputIterator last);

The first one requires the conversion of 5 to size_type (which is unsigned), while the second is a perfect match, so that will be the one picked up by the compiler...

第一个需要将5转换为size_type(它是无符号的),而第二个是一个完美的匹配,所以编译器会选中它……

... but the compiler requires that the second overload, if the deduced type InputIterator is integral behaves as if it was a call to:

…但编译器要求,如果推导出的类型InputIterator是整数,则第二个重载应表现为:

vector(static_cast<size_type>(first),static_cast<T>(last))

What the C++03 standard effectively mandates is that the second argument is explicitly converted from the original type int to the destination type std::vector<int>. Because the conversion is explicit you get the error.

c++ 03标准有效地要求第二个参数显式地从原始类型int转换为目标类型std::vector 。因为转换是显式的,所以会得到错误。

The C++11 standard changes the wording to use SFINAE to disable the iterator constructor if the argument is not really an input iterator, so in a C++11 compiler the code should be rejected (which is probably the reason some have claimed this to be a bug).

c++ 11标准修改了使用SFINAE禁用迭代器构造函数的措辞,如果参数不是一个输入迭代器,那么在c++ 11编译器中,代码应该被拒绝(这可能是一些人声称这是一个bug的原因)。

#2


2  

To me it looks like it's calling this constructor:

在我看来,它好像在调用构造函数:

template <class InputIterator>
vector (InputIterator first, InputIterator last,
  const allocator_type& alloc = allocator_type());

I'm not sure where explicit comes into it, because the constructor takes multiple parameters. It's not auto casting from an int to a vector.

我不确定显式在哪里,因为构造函数接受多个参数。它不是从int到向量的自动转换。

#3


1  

This is actually an extension, not a bug.

这实际上是一个扩展,而不是一个bug。

The constructor being invoked is the one that takes two iterators (but really, the signature will match any two parameters of the same type); it then invokes a specialization for when the two iterators are actually int, which explicitly constructs a value_type using the value of end and populates the vector with begin copies of it.

被调用的构造函数接受两个迭代器(但实际上,签名将匹配同一类型的任何两个参数);然后它调用一个专门化,当两个迭代器实际上是int时,它使用end的值显式地构造一个value_type,并使用开始复制的vector来填充这个向量。

#4


-4  

std::vector< int > has constructor that accepts size_type and const int&. This is the constructor I would expect to be called in this case, initializing the vector to have 5 ints, each with the value 5.

向量< int >具有接受size_type和const int&的构造函数。在这种情况下,我希望调用这个构造函数,初始化向量,使其具有5个int,每个ints的值为5。

#1


7  

It is not really a bug. The question is what could go wrong to allow the second piece of code while the first does not compile?

它不是真正的bug。问题是,当第一部分不编译时,允许第二部分代码出现错误的地方是什么?

The issue is that while it seems obvious to you what constructor you want to call when you do:

问题是,当你这么做的时候,你想调用什么构造函数是显而易见的:

std::vector<std::vector<int>> graph(5, 5);

it is not so clear for the compiler. In particular there are two constructor overloads that can potentially accept the arguments:

对编译器来说不是很清楚。特别是有两个构造函数重载可以接受参数:

vector(size_type,const T& value = T());

template <typename InputIterator>
vector(InputIterator first, InputIterator last);

The first one requires the conversion of 5 to size_type (which is unsigned), while the second is a perfect match, so that will be the one picked up by the compiler...

第一个需要将5转换为size_type(它是无符号的),而第二个是一个完美的匹配,所以编译器会选中它……

... but the compiler requires that the second overload, if the deduced type InputIterator is integral behaves as if it was a call to:

…但编译器要求,如果推导出的类型InputIterator是整数,则第二个重载应表现为:

vector(static_cast<size_type>(first),static_cast<T>(last))

What the C++03 standard effectively mandates is that the second argument is explicitly converted from the original type int to the destination type std::vector<int>. Because the conversion is explicit you get the error.

c++ 03标准有效地要求第二个参数显式地从原始类型int转换为目标类型std::vector 。因为转换是显式的,所以会得到错误。

The C++11 standard changes the wording to use SFINAE to disable the iterator constructor if the argument is not really an input iterator, so in a C++11 compiler the code should be rejected (which is probably the reason some have claimed this to be a bug).

c++ 11标准修改了使用SFINAE禁用迭代器构造函数的措辞,如果参数不是一个输入迭代器,那么在c++ 11编译器中,代码应该被拒绝(这可能是一些人声称这是一个bug的原因)。

#2


2  

To me it looks like it's calling this constructor:

在我看来,它好像在调用构造函数:

template <class InputIterator>
vector (InputIterator first, InputIterator last,
  const allocator_type& alloc = allocator_type());

I'm not sure where explicit comes into it, because the constructor takes multiple parameters. It's not auto casting from an int to a vector.

我不确定显式在哪里,因为构造函数接受多个参数。它不是从int到向量的自动转换。

#3


1  

This is actually an extension, not a bug.

这实际上是一个扩展,而不是一个bug。

The constructor being invoked is the one that takes two iterators (but really, the signature will match any two parameters of the same type); it then invokes a specialization for when the two iterators are actually int, which explicitly constructs a value_type using the value of end and populates the vector with begin copies of it.

被调用的构造函数接受两个迭代器(但实际上,签名将匹配同一类型的任何两个参数);然后它调用一个专门化,当两个迭代器实际上是int时,它使用end的值显式地构造一个value_type,并使用开始复制的vector来填充这个向量。

#4


-4  

std::vector< int > has constructor that accepts size_type and const int&. This is the constructor I would expect to be called in this case, initializing the vector to have 5 ints, each with the value 5.

向量< int >具有接受size_type和const int&的构造函数。在这种情况下,我希望调用这个构造函数,初始化向量,使其具有5个int,每个ints的值为5。