Страницы

Поиск по вопросам

суббота, 1 февраля 2020 г.

конструирование контейнера из потока ввода

#cpp


Конструировать и инициализировать вектор можно различными способами. Например можно
создать вектор двумя итераторами другого контейнера:

std::list list{3, 5, 6, 7, 8};
std::vector v1,  v2(list.begin(), list.end());


можно также заполнить его  прямо из потока ввода:

std::copy(std::istream_iterator(std::cin), 
          std::istream_iterator(), std::back_inserter(v1));


Вопрос:  почему же  нельзя конструировать вектор из потока ввода, как с первым примером?
Например, если написать:

std::vector 
v3(std::istream_iterator(std::cin), std::istream_iterator());
for (int i : v3)
    std::cout << i <<' ';


то выдается ошибка:

/* error: no matching function for call to
 'begin(std::vector (&)(std::istream_iterator, std::istream_iterator
(*)()))'
      for (int i : v3)
                 ^*/

    


Ответы

Ответ 1



Дело не в конструировании и инициализации вектора. Ваше сообщение об ошибке говорит о том, что ваше объявление v3 было проинтерпретировано как объявление функции. Это [похоже на] баг (?) компилятора. Он неправильно (?) обработал most vexing parse. Замените хотя бы внешние () на {} в инициализации std::vector v3{ std::istream_iterator(std::cin), std::istream_iterator() }; Что интересно, таким "багом" страдают MSVC++ и Clang. Кто же тут прав? Эта тема здесь уже всплывала, но что-то я не могу ее найти. Также: Most vexing parse with a qualified-id - or not?

Ответ 2



Конструировать напрямую из istream_iterator можно, но судя по сообщению об ошибке, тут сработал most vexing parse. C точки зрения вашего компилятора, строка std::vector v3(std::istream_iterator(std::cin), std::istream_iterator()); выглядит одновременно как определение переменной v3 типа std::vector и объявление функции v3 с возвращаемым типом std::vector и двумя параметрами: типа std::istream_iterator с именем std::cin. Скобки вокруг имени игнорируются. Но :: в имени параметра - нонсенс. Насколько я понимаю, тут компилятор неправ - имя параметра не может содержать ::. GCC 8.2 компилирует эту строчку без ошибок, а Clang 7 ругается на ::. И то и другое явно более правильно. (Поведение GCC кажется мне более разумным, но я не знаю, что по этому поводу говорит стандарт.) типа std::istream_iterator (*)() (указатель на функцию без аргументов, возвращающую std::istream_iterator). В исходной строке звездочки не было, но параметры, являющиеся функциями, автоматически преобразуются в указатели на функции. (Подобно тому, как параметры-массивы преобразуются в указатели.) В таких случаях компилятор всегда истолковывает такие неоднозначные конструкции как объявления функций. Это и называется "most vexing parse", то есть "наиболее раздражающий парсинг" (потому что это часто застает программистов врасплох). Чтобы исправить ошибку, нужно изменить строчку так, чтобы она явно не выглядела как объявление функции. Например так: std::vector v3(std::istream_iterator(std::cin), std::istream_iterator{}); Или так: std::vector v3((std::istream_iterator(std::cin)), std::istream_iterator());

Комментариев нет:

Отправить комментарий