Программа будет компилироваться, но во время выполнения она ничего не сделает. Она не прочитает данные из файла. Она даже не создаст список — а все потому, что вторая команда не объявляет список и не вызывает конструктор. Вместо этого она... Произойдет нечто настолько странное, что я даже не рискну прямо сказать об этом, потому что вы мне не поверите. Вместо этого я попробую объяснить суть дела постепенно, шаг за шагом. Надеюсь, вы сидите? Если нет — лучше поищите стул...

Начнем с азов. Следующая команда объявляет функцию f, которая получает double и возвращает int:

int f(double d);

То же самое происходит и в следующей строке. Круглые скобки вокруг имени параметра d не нужны, поэтому компилятор их игнорирует:

int f(double(d));// То же,- круглые скобки вокруг d игнорируются

Рассмотрим третий вариант объявления той же функции. В нем просто не указано имя параметра:

int f(double);// То же; имя параметра не указано

Вероятно, эти три формы объявления вам знакомы, хотя о возможности заключать имена параметров в скобки известно далеко не всем (до недавнего времени я о ней не знал).

Теперь рассмотрим еще три объявления функции. В первом объявляется функция g с параметром — указателем на функцию, которая вызывается без параметров и возвращает double:

int g(double (*pf)()); // Функции g передается указатель на функцию

То же самое можно сформулировать и иначе. Единственное различие заключается в том, что pf объявляется в синтаксисе без указателей (допустимом как в С, так и в С++):

int g(double pf()); // То же; pf неявно интерпретируется как указатель

Как обычно, имена параметров могут опускаться, поэтому возможен и третий вариант объявления g без указания имени pf:

int g(double());// То же: имя параметра не указано

Обратите внимание на различия между круглыми скобками вокруг имени параметра (например, параметра d во втором объявлении f) и стоящими отдельно (как в этом примере). Круглые скобки, в которые заключено имя параметра, игнорируются, а круглые скобки, стоящие отдельно, обозначают присутствие списка параметров; они сообщают о присутствии параметра, который является указателем на функцию.

После небольшой разминки с объявлениями f и g мы возвращаемся к фрагменту, с которого начинается этот совет. Ниже он приводится снова:

list data(istream_iterator(dataFile),

istream_iterator());

Держитесь и постарайтесь не упасть. Перед вами объявление функции data, возвращающей тип list. Функция data получает два параметра:

•Первый параметр, dataFile, относится к типу istream_iterator. Лишние круглые скобки вокруг dataFile игнорируются.

•Второй параметр не имеет имени. Он относится к типу указателя на функцию, которая вызывается без параметров и возвращает istream_iterator.

Любопытно, не правда ли? Однако такая интерпретация соответствует одному из основных правил С++: все, что может интерпретироваться как указатель на функцию, должно интерпретироваться именно так. Каждый программист с опытом работы на С++ встречался с теми или иными воплощениями этого правила. Сколько раз вы встречались с такой ошибкой:

class Widget{...};// Предполагается, что у Widget

// имеется конструктор по умолчанию

Widget w();// Какая неприятность...

Вместо объекта класса Widget с именем w в этом фрагменте объявляется функция w, которая вызывается без параметров и возвращает Widget. Умение распознавать подобные «ляпы» — признак хорошей квалификации программиста С++.

Все это по-своему интересно, однако мы нисколько не приблизились к поставленной цели: инициализировать объект list содержимым файла. Зато теперь мы знаем, в чем заключается суть проблемы, и легко справимся с ней. Объявления формальных параметров не могут заключаться в круглые скобки, но никто не запрещает заключить в круглые скобки аргумент при вызове функции, поэтому простое добавление круглых скобок поможет компилятору увидеть происходящее под нужным углом зрения:

list data((istream_iterator(dataFile)), // Обратите внимание istream_iterator()); // на круглые скобки

// вокруг первого аргумента

// конструктора list

Именно так следует объявлять данные. Учитывая практическую полезность istream_iterator и интервальных конструкторов (совет 5), этот прием стоит запомнить.

Перейти на страницу:

Все книги серии Библиотека программиста

Похожие книги