用宏构造#include指令的路径

Ric*_*ges 12 c++ macros include boost-preprocessor

我想为宏程序动态创建的包含文件路径,用于程序的目标配置相关部分.

例如,我想构建一个可以像这样调用的宏:

#include TARGET_PATH_OF(header.h)
Run Code Online (Sandbox Code Playgroud)

这会扩展到这样的事情:

#include "corefoundation/header.h"
Run Code Online (Sandbox Code Playgroud)

当为OSX配置源(在本例中)时

到目前为止,所有尝试都失败了 我希望以前有人这样做过吗?

什么不起作用的例子:

#include <iostream>
#include <boost/preprocessor.hpp>

#define Dir directory/
#define File filename.h

#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
#define MyPath MakePath(File)

using namespace std;

int main() {
    // this is a test - yes I know I could just concatenate strings here
    // but that is not the case for #include
    cout << MyPath << endl;
}
Run Code Online (Sandbox Code Playgroud)

错误:

./enableif.cpp:31:13: error: pasting formed '/filename', an invalid preprocessing token
    cout << MyPath << endl;
            ^
./enableif.cpp:26:16: note: expanded from macro 'MyPath'
#define MyPath MakePath(File)
               ^
./enableif.cpp:25:40: note: expanded from macro 'MakePath'
#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
                                       ^
/usr/local/include/boost/preprocessor/cat.hpp:22:32: note: expanded from macro 'BOOST_PP_CAT'
#    define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b)
                               ^
/usr/local/include/boost/preprocessor/cat.hpp:29:36: note: expanded from macro 'BOOST_PP_CAT_I'
#    define BOOST_PP_CAT_I(a, b) a ## b
                                   ^
1 error generated.
Run Code Online (Sandbox Code Playgroud)

ric*_*ici 14

我倾向于同意utnapistim的答案中的评论,即使你可以,你也不应该这样做.但实际上,您可以使用符合标准的C编译器.[注1]

有两个问题需要克服.第一个是你不能使用##运算符来创建一个不是有效的预处理器标记的东西,并且路径名不符合有效的预处理器标记,因为它们包含/.字符.(.如果令牌以数字开头,那/就没问题,但是永远不会有效.)

实际上,您不需要连接标记以便将它们与#运算符进行字符串化,因为该运算符将对整个宏参数进行字符串化,并且参数可能包含多个标记.但是,stringify尊重空格[注2],所以STRINGIFY(Dir File)不起作用; 它会导致"directory/ filename.h"文件名中的无关空间导致#include失败.所以你需要连接Dir并且File没有任何空格.

下面通过使用类似函数的宏来解决第二个问题,它只返回它的参数:

#define IDENT(x) x
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define PATH(x,y) STR(IDENT(x)IDENT(y))

#define Dir sys/
#define File socket.h

#include PATH(Dir,File)
Run Code Online (Sandbox Code Playgroud)

请注意,Dir将保留调用中的空白字符.所以File会失败.

当然,unix如果你可以编写没有空格的连接,你就不需要宏的复杂性.例如:

#define XSTR(x) #x
#define STR(x) XSTR(x)

#define Dir sys
#define File socket.h

#include STR(Dir/File)
Run Code Online (Sandbox Code Playgroud)

笔记

  1. 我用godbolt上的clang,gcc和icc尝试过它.我不知道它是否适用于Visual Studio.

  2. 更准确地说,它半空间:空白空间被转换为单个空格字符.