web-dev-qa-db-ja.com

#includeディレクティブを含むマクロ定義

本体に#includeディレクティブを含むマクロを定義する方法はありますか?

"#include"だけを入力すると、エラーが発生します

C2162: "expected macro formal parameter"

ここでは、#を使用して文字列を連結していません。
\# include」を使用すると、次の2つのエラーが表示されます。

error C2017: illegal escape sequence
error C2121: '#' : invalid character : possibly the result of a macro expansion

何か助けは?

34
Bing Jian

したがって、他の人が言うように、プリプロセッサは1つのパスしか実行しないため、マクロ内に#includeステートメントを含めることはできません。ただし、最近使用した危険なトリックを使用して、プリプロセッサーに基本的に同じことを実行させることができます。

プリプロセッサディレクティブはマクロ内では何も実行しないことを認識してください。ただし、それらはファイル内で何かを実行します。そのため、変更したいコードのブロックをファイルに貼り付け、それをマクロ定義のように考えて(他のマクロによって変更される可能性のある部分を含む)、次にこの疑似マクロファイルをさまざまな場所に#include(makeインクルードガードがないことを確認してください!)マクロのようには動作しませんが、#includeは基本的に1つのファイルの内容を別のファイルにダンプするだけなので、かなりマクロのような結果を得ることができます。

たとえば、グループ化された類似した名前のヘッダーを多数含めることを検討してください。それらをすべて書き出すことは退屈で、おそらく自動生成されます。次のようにすることで、それらの包含を部分的に自動化できます。

ヘルパーマクロヘッダー:

/* 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

疑似マクロファイル

/* 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.

これらのインクルードは、Bing Jianリクエストの回答として、繰り返したいコードブロックの途中にある可能性もあります(FOOを変更した場合)。 #includeディレクティブを含むマクロ定義

私はこのトリックを広範囲に使用したことはありませんが、私の仕事を成し遂げることができます。これは明らかに拡張して、必要な数の「パラメーター」を持たせることができ、そこで好きなプリプロセッサーコマンドを実行して、実際のコードを生成できます。マクロ内にインクルードを貼り付けることができないため、通常のマクロと同様に、それが別のマクロへの入力として作成するものを使用することはできません。しかし、それは別の疑似マクロの中に入ることができます:)。

他の人は他の制限についてのいくつかのコメントを持っているかもしれません、そして何がうまくいかないかもしれません:)。

21
Ben Farmer

そのメリットについては議論しませんが、freetype(www.freetype.org)は次のことを行います。

#include FT_FREETYPE_H

他の場所でFT_FREETYPE_Hを定義する場所

13
Dan Hewett

CおよびC++言語では、マクロ展開の結果としてのプリプロセッサーディレクティブの形成を明示的に禁止しています。つまり、プリプロセッサディレクティブをマクロ置換リストに含めることはできません。また、連結によって新しいプリプロセッサディレクティブを "構築"してプリプロセッサをだまそうとする場合(およびそのようなトリック)、動作は未定義です。

6
AnT

C/C++プリプロセッサはコードを1回だけパスすると信じているので、それがうまくいくとは思いません。マクロによって「#include」をコードに配置できる可能性がありますが、コンパイラーはそれをどうするかわからないため、コンパイラーがそれを抑制します。プリプロセッサーを動作させるために何をしようとしているのかについては、#includeを取得するために、ファイルに対して2回目のパスを実行する必要があります。

5
Herms

私もこれをやりたかったのですが、これが理由です。

CまたはC++でコンパイルしている場合、一部のヘッダーファイル(特にOpenMPIのmpi.h)の動作が異なります。 C MPIコードにリンクしています。ヘッダーを含めるには、通常どおり行います。

extern "C" {
#include "blah.h"
}

ただし、Cリンケージでも__cplusplusが定義されているため、これは機能しません。これは、blah.hに含まれているmpi.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を定義したいと思います。しかし、それはうまくいかないと思います。

誰かがこれを達成する別の方法を理解できる場合は、私に知らせてください。

4
Lutorm

私も得たので、このタスクは不可能に思えるので大丈夫だと思います

http://groups.google.com/group/comp.lang.c++/browse_thread/thread/03d20d234539a85c#

いいえ、C++(およびC)のプリプロセッサディレクティブは反映されません。

パヴェル・ジエパック

とにかく、この試みの背後にある理由は、次の繰り返し使用されるコードスニペットをマクロとして作成しようとしているためです。

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」です。

3
Bing Jian

マクロに#includeが必要なのはなぜですか?マクロが含まれているファイルを#includeしている場合は、残りのすべての#includeステートメントと共に#includeをマクロの上に置くだけで、すべてがナイスでダンディでなければなりません。

マクロにファイルに含めることができなかったものを含める理由はありません。

1
helloandre

あなたが実際に何をしようとしているのか私にはわかりませんが、あなたが望むのはテンプレート関数のようです。

このように、PixelTypeはコードのブロックへの単なるテンプレートパラメーターです。

0
user21714