Неявное преобразование из int в вектор?

vector<T> имеет конструктор, который принимает размер вектора, и, насколько я знаю, он является явным, что может быть доказано тем фактом, что следующий код не может скомпилировать

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

Я не могу понять и прошу вас объяснить, почему следующий код компилируется

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

Он не только компилирует, он фактически изменяет размер графа до 5 и устанавливает каждый элемент в вектор из пяти нулей, то есть делает то же самое, что и код, который я обычно пишу:

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

Как? Зачем?

Компилятор: MSVC10.0


ОК, похоже, это ошибка MSVC (еще одна). Если кто-то может уточнить ошибку в ответе (т.е. обобщить случаи, когда она воспроизводится), я с радостью приму ее

4 ответа

Решение

Это не совсем ошибка. Вопрос в том, что может пойти не так, чтобы разрешить второй кусок кода, пока первый не компилируется?

Проблема в том, что, хотя для вас очевидно, какой конструктор вы хотите вызвать, когда вы это делаете:

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

это не очень понятно для компилятора. В частности, есть две перегрузки конструктора, которые могут потенциально принимать аргументы:

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

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

Первый требует преобразования 5 в size_type (без знака), в то время как второй - идеальное совпадение, так что это будет тот, который подобрал компилятор...

... но компилятору требуется вторая перегрузка, если выводится тип InputIterator Интеграл ведет себя так, как если бы это был вызов:

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

Что в стандарте C++03 фактически предписывается, так это то, что второй аргумент явно преобразуется из исходного типа int к типу назначения std::vector<int>, Поскольку преобразование явное, вы получаете ошибку.

Стандарт C++11 изменяет формулировку, чтобы использовать SFINAE для отключения конструктора итератора, если аргумент на самом деле не является входным итератором, поэтому в компиляторе C++11 код должен быть отклонен (что, вероятно, является причиной, по которой некоторые утверждают, что это быть ошибкой).

Мне кажется, это вызывает этот конструктор:

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

Я не уверен где explicit входит в это, потому что конструктор принимает несколько параметров. Это не автоматическое приведение от int к вектору.

На самом деле это расширение, а не ошибка.

Вызываемый конструктор - это тот, который принимает два итератора (но на самом деле сигнатура будет соответствовать любым двум параметрам одного типа); Затем он вызывает специализацию, когда два итератора на самом деле int, который явно создает value_type используя значение end и заполняет вектор begin копии этого.

std::vector имеет конструктор, который принимает size_type и const int&. Это тот конструктор, который я бы ожидал вызвать в этом случае, инициализируя вектор 5-ю целыми числами, каждое со значением 5.

Другие вопросы по тегам