Определение макроса, содержащее директиву #include
Есть ли способ определить макрос, который может содержать #include
директива в ее теле?
Если я просто поставлю
"#include
", он дает ошибку
C2162: "expected macro formal
Параметр "
так как здесь я не использую #
для конкатенации строк.
Если я использую "\# include
", я получаю следующие две ошибки:
error C2017: illegal escape sequence
error C2121: '#' : invalid character : possibly the result of a macro expansion
Любая помощь?
Ответы
Ответ 1
Так, как говорят другие, нет, у вас не может быть операторов #include внутри макроса, поскольку препроцессор выполняет только один проход. Тем не менее, вы можете заставить препроцессор сделать в основном то же самое с грубым трюком, который я недавно использовал.
Поймите, что директивы препроцессора ничего не сделают внутри макроса, однако они что-то сделают в файле. Таким образом, вы можете вставить блок кода, который хотите изменить, в файл, считая его как определение макроса (с кусками, которые могут быть изменены другими макросами), а затем # включить этот псевдомакрофайл в разных местах (make уверен, что у него нет охранников!). Он не ведет себя точно так же, как макрос, но он может достичь некоторых довольно макроподобных результатов, поскольку #include в основном просто выгружает содержимое одного файла в другой.
Например, рассмотрим включение много похожих заголовков, которые входят в группы. Довольно утомительно писать все, или, может быть, они автоматически генерируются. Вы можете частично автоматизировать их включение, выполнив что-то вроде этого:
Заголовок макроса помощника:
/* tools.hpp */
#ifndef __TOOLS_HPP__
#def __TOOLS_HPP__
// Macro for adding quotes
#define STRINGIFY(X) STRINGIFY2(X)
#define STRINGIFY2(X) #X
// Macros for concatenating tokens
#define CAT(X,Y) CAT2(X,Y)
#define CAT2(X,Y) X##Y
#define CAT_2 CAT
#define CAT_3(X,Y,Z) CAT(X,CAT(Y,Z))
#define CAT_4(A,X,Y,Z) CAT(A,CAT_3(X,Y,Z))
// etc...
#endif
Pseudo-macro file
/* pseudomacro.hpp */
#include "tools.hpp"
// NO INCLUDE GUARD ON PURPOSE
// Note especially FOO, which we can #define before #include-ing this file,
// in order to alter which files it will in turn #include.
// FOO fulfils the role of "parameter" in this pseudo-macro.
#define INCLUDE_FILE(HEAD,TAIL) STRINGIFY( CAT_3(HEAD,FOO,TAIL) )
#include INCLUDE_FILE(head1,tail1.hpp) // expands to #head1FOOtail1.hpp
#include INCLUDE_FILE(head2,tail2.hpp)
#include INCLUDE_FILE(head3,tail3.hpp)
#include INCLUDE_FILE(head4,tail4.hpp)
// etc..
#undef INCLUDE_FILE
Исходный файл
/* mainfile.cpp */
// Here we automate the including of groups of similarly named files
#define FOO _groupA_
#include "pseudomacro.hpp"
// "expands" to:
// #include "head1_groupA_tail1.hpp"
// #include "head2_groupA_tail2.hpp"
// #include "head3_groupA_tail3.hpp"
// #include "head4_groupA_tail4.hpp"
#undef FOO
#define FOO _groupB_
#include "pseudomacro.hpp"
// "expands" to:
// #include "head1_groupB_tail1.hpp"
// #include "head2_groupB_tail2.hpp"
// #include "head3_groupB_tail3.hpp"
// #include "head4_groupB_tail4.hpp"
#undef FOO
#define FOO _groupC_
#include "pseudomacro.hpp"
#undef FOO
// etc.
Они включают даже в середине блоков кодов, которые вы хотите повторить (с изменением FOO), так как ответ Bing Jian запрашивает: определение макроса, содержащее директиву #include
Я не использовал этот трюк широко, но он выполняет мою работу. Очевидно, что он может быть расширен, чтобы иметь столько "параметров", сколько необходимо, и вы можете запускать любые команды препроцессора, которые вам нравятся, плюс генерировать фактический код. Вы просто не можете использовать материал, который он создает, как ввод в другой макрос, как вы можете с помощью обычных макросов, так как вы не можете вставлять внутри макроса. Но он может войти в другой псевдомакро:).
Другие могут иметь некоторые комментарии к другим ограничениям, и что может пойти не так:).
Ответ 2
Я не буду спорить о его достоинствах, но freetype (www.freetype.org) делает следующее:
#include FT_FREETYPE_H
где они определяют FT_FREETYPE_H в другом месте
Ответ 3
Языки C и С++ явно запрещают формирование директив препроцессора в результате расширения макросов. Это означает, что вы не можете включить директиву препроцессора в список замены макросов. И если вы попытаетесь обмануть препроцессор, "построив" новую директиву препроцессора посредством конкатенации (и трюки), поведение undefined.
Ответ 4
Я считаю, что препроцессор C/С++ выполняет только один проход над кодом, поэтому я не думаю, что это сработает. Возможно, вы сможете получить "#include", который будет помещен в код макросом, но компилятор задушит его, поскольку он не знает, что с этим делать. Для того, что вы пытаетесь сделать для работы, препроцессор должен будет сделать второй проход над файлом, чтобы получить #include.
Ответ 5
Я тоже хотел это сделать, и вот причина:
Некоторые файлы заголовков (особенно mpi.h в OpenMPI) работают по-разному, если вы компилируете на C или С++. Я связываюсь с кодом C MPI из моей программы на С++. Чтобы включить заголовок, я делаю обычное:
extern "C" {
#include "blah.h"
}
Но это не работает, потому что __cplusplus
по-прежнему определяется даже в C-ссылке. Это означает, что mpi.h, который включен blah.h, начинает определять шаблоны, а компилятор умирает, говоря, что вы не можете использовать шаблоны с C-связью.
Следовательно, то, что я должен сделать в blah.h, заключается в замене
#include <mpi.h>
с
#ifdef __cplusplus
#undef __cplusplus
#include <mpi.h>
#define __cplusplus
#else
#include <mpi.h>
#endif
Примечательно, что это не только mpi.h, что делает эту патологическую вещь. Следовательно, я хочу определить макрос INCLUDE_AS_C
, который делает выше для указанного файла. Но я думаю, что это не сработает.
Если кто-то может понять другой способ выполнения этого, сообщите мне.
Ответ 6
Я думаю, что вы в порядке, потому что эта задача кажется невозможной, поскольку я также получил от
http://groups.google.com/group/comp.lang.c++/browse_thread/thread/03d20d234539a85c#
Нет, директивы препроцессора в С++ (и C) не являются отражающими.
Pawel Dziepak
В любом случае причина этой попытки заключается в том, что я пытаюсь сделать следующее
многократно использовал фрагмент кода в качестве макроса:
void foo(AbstractClass object)
{
switch (object.data_type())
{
case AbstractClass::TYPE_UCHAR :
{
typedef unsigned char PixelType;
#include "snippets/foo.cpp"
}
break;
case AbstractClass::TYPE_UINT:
{
typedef unsigned int PixelType;
#include "snippets/foo.cpp"
}
break;
default:
break;
}
}
Для другой задачи мне нужна аналогичная функция
void bar(AbstractClass object)
где я поставлю
#include "snippets/bar.cpp"
и, конечно, в "snippets/foo.cpp" и "snippets/bar.cpp" записывается код, специфичный для конкретной задачи.
Ответ 7
Зачем макросу нужно иметь #include? если вы # включаете какой-либо файл, в котором находится макрос, вы можете просто положить #include над макросом со всеми остальными операторами #include, и все должно быть красивым и денди.
Я не вижу причины, чтобы макрос включал все, что не могло быть просто включено в файл.
Ответ 8
Я понятия не имею, что вы на самом деле пытаетесь сделать, но похоже, что вам может понадобиться шаблонная функция.
Таким образом, PixelType является всего лишь параметром шаблона блока кода.
Ответ 9
Контагиозный - это правильно - если вы делаете:
myFile.c:
#include "standardAppDefs.h"
#myStandardIncludeMacro
standardAppDefs.h:
#define myStandardIncludeMacro #include <foo.h>
Почему бы просто не сказать:
myFile.c:
#include "standardAppDefs.h"
standardAppDefs.h:
#include <foo.h>
И забыли макросы?