Неявное преобразование из 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