// вы предполагали
Идея проста: передать пару istream_iterator
интервальному конструктору list
(совет 5), после чего скопировать числа из файла в список.
Программа будет компилироваться, но во время выполнения она ничего не сделает. Она не прочитает данные из файла. Она даже не создаст список — а все потому, что вторая команда не объявляет список и не вызывает конструктор. Вместо этого она… Произойдет нечто настолько странное, что я даже не рискну прямо сказать об этом, потому что вы мне не поверите. Вместо этого я попробую объяснить суть дела постепенно, шаг за шагом. Надеюсь, вы сидите? Если нет — лучше поищите стул…
Начнем с азов. Следующая команда объявляет функцию f
, которая получает double
и возвращает int
:
int f(double d);
То же самое происходит и в следующей строке. Круглые скобки вокруг имени параметра d
не нужны, поэтому компилятор их игнорирует:
int f(double(d));// То же,- круглые скобки вокруг d игнорируются
Рассмотрим третий вариант объявления той же функции. В нем просто не указано имя параметра:
int f(double);// То же; имя параметра не указано
Вероятно, эти три формы объявления вам знакомы, хотя о возможности заключать имена параметров в скобки известно далеко не всем (до недавнего времени я о ней не знал).
Теперь рассмотрим еще три объявления функции. В первом объявляется функция g
с параметром — указателем на функцию, которая вызывается без параметров и возвращает double
:
int g(double (*pf)); // Функции g передается указатель на функцию
То же самое можно сформулировать и иначе. Единственное различие заключается в том, что pf
объявляется в синтаксисе без указателей (допустимом как в C, так и в C++):
int g(double pf); // То же; pf неявно интерпретируется как указатель
Как обычно, имена параметров могут опускаться, поэтому возможен и третий вариант объявления g
без указания имени pf
:
int g(double);// То же: имя параметра не указано
Обратите внимание на различия между круглыми скобками d
во втором объявлении f
) и
После небольшой разминки с объявлениями f
и g
мы возвращаемся к фрагменту, с которого начинается этот совет. Ниже он приводится снова:
list
Держитесь и постарайтесь не упасть. Перед вами объявление data
, возвращающей тип list
. Функция data
получает два параметра:
• Первый параметр, dataFile
, относится к типу istream_iterator
. Лишние круглые скобки вокруг dataFile
игнорируются.
• Второй параметр не имеет имени. Он относится к типу указателя на функцию, которая вызывается без параметров и возвращает istream_iterator
Любопытно, не правда ли? Однако такая интерпретация соответствует одному из основных правил C++: все, что может интерпретироваться как указатель на функцию, должно интерпретироваться именно так. Каждый программист с опытом работы на C++ встречался с теми или иными воплощениями этого правила. Сколько раз вы встречались с такой ошибкой:
class Widget{...}; // Предполагается, что у Widget
// имеется конструктор по умолчанию
Widget w; // Какая неприятность...
Вместо объекта класса Widget
с именем w
в этом фрагменте объявляется функция w
, которая вызывается без параметров и возвращает Widget
. Умение распознавать подобные «ляпы» — признак хорошей квалификации программиста C++.
Все это по-своему интересно, однако мы нисколько не приблизились к поставленной цели: инициализировать объект list
содержимым файла. Зато теперь мы знаем, в чем заключается суть проблемы, и легко справимся с ней. Объявления формальных параметров не могут заключаться в круглые скобки, но никто не запрещает заключить в круглые скобки аргумент при вызове функции, поэтому простое добавление круглых скобок поможет компилятору увидеть происходящее под нужным углом зрения:
list
istream_iterator
// вокруг первого аргумента
// конструктора list