Вы когда-нибудь писали заголовок без охраны? - PullRequest
7 голосов
/ 14 октября 2011

Мне интересно, почему компиляторы C ++ не генерируют средства защиты заголовков автоматически для заголовков?

// Why do I have to write this for every .hpp file I create?!!
#ifndef myheader_hpp__
#define myheader_hpp__
// ...
#endif

Я не встречал ситуацию, когда они не нужны, когда я пишу свои заголовки.Я не вижу реального варианта использования противоположного поведения, но я был бы рад увидеть его.Есть техническая сложность или это просто история?!

Ответы [ 4 ]

10 голосов
/ 14 октября 2011
2 голосов
/ 14 октября 2011

Я просто укажу вам на проект Clang / LLVM.

В этом проекте они создали способ кодирования данных с использованием простого описательного языка, который затем подается в инструмент (называемый tblgen).для генератора таблиц), который предназначен для создания файла C ++.Например, диагностика :

let Component = "Sema" in {
let CategoryName = "Semantic Issue" in {

// Constant expressions
def err_expr_not_ice : Error<
  "expression is not an integer constant expression">;

....

В Clang имеется несколько тысяч диагностических сообщений, разделенных на несколько файлов.После обработки в tblgen они сгенерируют огромный файл .inc, который для каждой диагностики будет содержать вызов макроса.Определив макрос и включив файл, вы можете создать таблицу C ++ (или что-нибудь еще на самом деле, но, как правило, для таблиц):

static const StaticDiagInfoRec StaticDiagInfo[] = {
#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,               \
             SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,              \
             CATEGORY,BRIEF,FULL)                                 \
  { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS,           \
    NOWERROR, SHOWINSYSHEADER, CATEGORY,                          \
    STR_SIZE(#ENUM, uint8_t), STR_SIZE(GROUP, uint8_t),           \
    STR_SIZE(DESC, uint16_t), STR_SIZE(BRIEF, uint16_t),          \
    STR_SIZE(FULL, uint16_t),                                     \
    #ENUM, GROUP, DESC, BRIEF, FULL },
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
#include "clang/Basic/DiagnosticLexKinds.inc"
#include "clang/Basic/DiagnosticParseKinds.inc"
#include "clang/Basic/DiagnosticASTKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

И те же файлы могутсоздавать разные таблицы, поскольку вы можете писать макросы по своему желанию.

Это, конечно, очень специфическое использование.

Но не волнуйтесь, даже если модули нене сделаем это в C ++ 11, мы можем надеяться на C ++ 1x.

2 голосов
/ 14 октября 2011

Потому что это универсальный механизм для вставки одного файла в другой.

Просто способность общего назначения используется для очень общей специфической цели в 99% случаев.

2 голосов
/ 14 октября 2011

Для компилятора автоматическое включение include guard не является действительно практичным. Вы можете определить прототипы для методов / функций / классов / и т. Д., Не сталкиваясь с проблемами, и обычно это делается в заголовке. Однако, когда класс определен в заголовке, вы сталкиваетесь с проблемой определения класса более одного раза компилятором, если он включен в два разных файла .cpp или другие заголовки.

Действительно, включить охранников - это всего лишь один трюк для заголовков. Вы не всегда нуждаетесь в них, и в некоторых случаях вы бы их не использовали. Это на самом деле проще, хотите верьте, хотите нет.

...