Целевые переменные как предпосылки в make-файле

В эта статья DDJ, Dan Saks объясняет одну небольшую площадь, где ошибки могут вползти через, если Вы не делаете определения типа Ваши структуры (и классы!):

, Если Вы хотите, можно предположить, что C++ генерирует определение типа для каждого имени тега, такой как [1 114]

typedef class string string;

, К сожалению, это не совсем точно. Мне жаль, что это не было настолько просто, но это не. C++ не может генерировать такие определения типов для структур, объединений или перечислений, не начиная несовместимости с C.

, Например, предположите, что программа C объявляет и функцию и структуру, названную состоянием:

int status(); struct status;

Снова, это может быть плохой практикой, но это - C. В этой программе состояние (отдельно) относится к функции; состояние структуры относится к типу.

, Если бы C++ действительно автоматически генерировал определения типов для тегов, то при компиляции этой программы как C++ компилятор генерировал бы:

typedef struct status status;

, К сожалению, это имя типа конфликтовало бы с именем функции, и программа не скомпилирует. Вот почему C++ не может просто генерировать определение типа для каждого тега.

В C++, действие тегов точно так же, как имена определения типа, за исключением того, что программа может объявить объект, функцию или перечислитель с тем же именем и тем же объемом как тег. В этом случае объект, функция или имя перечислителя скрывают имя тега. Программа может относиться к имени тега только при помощи класса ключевого слова, структуры, объединения или перечисления (как соответствующая) перед именем тега. Имя типа, состоящее из одного из этих ключевых слов, сопровождаемых тегом, является elaborated-type-specifier. Например, состояние структуры и перечислимый месяц является elaborated-type-specifiers.

Таким образом, программа C, которая содержит обоих:

int status(); struct status;

ведет себя то же при компиляции как C++. Одно только состояние имени относится к функции. Программа может относиться к типу только при помощи elaborated-type-specifier состояния структуры.

Поэтому, как это позволяет ошибкам вползать в программы? Рассмотрите программу в Список 1 . Эта программа определяет нечто класса с конструктором по умолчанию и оператор преобразования, который преобразовывает объект нечто обуглить константу *. Выражение

p = foo();

в основном должно создать объект нечто и применить оператор преобразования. Последующий оператор вывода

cout << p << '\n';

должен отобразить нечто класса, но это не делает. Это отображает функциональное нечто.

Этот неожиданный результат происходит, потому что программа включает заголовок lib.h показанный в [1 110] Список 2 . Этот заголовок определяет функцию, также названную нечто. Нечто имени функции скрывает нечто имени класса, таким образом, ссылка на нечто в основном относится к функции, не классу. основной может относиться к классу только при помощи elaborated-type-specifier, как в [1 126]

p = class foo();

способ избежать, чтобы такой беспорядок всюду по программе добавил следующее определение типа для нечто имени класса:

typedef class foo foo;

сразу прежде или после определения класса. Это определение типа вызывает конфликт между нечто имени типа и нечто имени функции (из библиотеки), который инициирует ошибку времени компиляции.

я не знаю ни о ком, кто на самом деле пишет эти определения типов как само собой разумеющееся. Требуется большая дисциплина. Начиная с падения ошибок, таких как та в [1 111] Список 1 является, вероятно, довольно маленьким, Вы многие никогда не сталкиваются с этой проблемой. Но если ошибка в Вашем программном обеспечении могла бы нанести телесные повреждения, то необходимо записать определения типов, неважно, как вряд ли ошибка.

я не могу вообразить, почему любой когда-либо хотел бы скрыть имя класса с именем функции или именем объекта в том же объеме как класс. Скрывающиеся правила в C были ошибкой, и они не должны были быть расширены на классы в C++. Действительно, можно исправить ошибку, но она требует дополнительной дисциплины программирования и усилия, которое не должно быть необходимо.

14
задан Nimrod Gileadi 27 August 2009 в 10:35
поделиться

2 ответа

Целевая переменная определяется только в целевых командах (или в других целевых назначениях); его нельзя использовать как одно из предварительных требований цели. Я не думаю, что есть чистый способ делать то, что вы хотите, в Make, но есть несколько беспорядочных подходов, например следующий:

EXTENSIONS = .exta .extb
target_1: $(addprefix target1_prereq,$(EXTENSIONS))
target_2: $(addprefix target2_prereq,$(EXTENSIONS))

target_1 target_2: common_filename
    do_something common_filename --a-weird-option=$(filter %.exta,$^) --second=$(filter %.extb,$^)
3
ответ дан 1 December 2019 в 16:15
поделиться

В качестве простого обходного пути:

target_1:special_filename=target1_prereq
target_1:target1_prereq
target_2:special_filename=target2_prereq
target_2:target2_prereq

target_1 target_2: common_filename $(special_filename)
    do_something common_filename --a-weird-option=$(special_filename)

Есть некоторая избыточность, но она локализована, так что это не так уж плохо.

3
ответ дан 1 December 2019 в 16:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: