名前空間
変種
操作

テキストマクロの置換

From cppreference.com
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

プリプロセッサはテキストマクロ置換をサポートしています。関数形式のテキストマクロ置換もサポートされています。

目次

[編集] 構文

#define 識別子 置換リスト (オプション) (1)
#define 識別子 (パラメータ ) 置換リスト (オプション) (2)
#define 識別子 (パラメータ , ...) 置換リスト (オプション) (3) (C++11以降)
#define 識別子 (...) 置換リスト (オプション) (4) (C++11以降)
#undef 識別子 (5)

[編集] 説明

[編集] #define ディレクティブ

#define ディレクティブは、識別子をマクロとして定義します。つまり、コンパイラに識別子のほとんどの連続する出現を置換リストに置き換えるように指示し、これはさらに処理されます。スキャンと置換のルールから例外が生じます。識別子が既に何らかの種類のマクロとして定義されている場合、定義が同一でない限り、プログラムは不正な形式です。

[編集] オブジェクト形式マクロ

オブジェクト形式マクロは、定義された識別子のすべての出現を置換リストに置き換えます。#define ディレクティブのバージョン (1) は、まさにそのように動作します。

[編集] 関数形式マクロ

関数形式マクロは、定義された識別子の各出現を置換リストに置き換え、さらにいくつかの引数を取り、それらの引数は置換リスト内のパラメータの対応する出現を置き換えます。

関数形式マクロ呼び出しの構文は関数呼び出しの構文と似ています。マクロ名の後に次のプリプロセスートークンとして(が続く各インスタンスは、置換リストによって置き換えられるトークンのシーケンスを導入します。シーケンスは、対応する左右の括弧の間のペアをスキップして、対応する)トークンで終了します。

バージョン (2) の場合、引数の数はマクロ定義のパラメータの数と同じでなければなりません。バージョン (3,4) の場合、引数の数はパラメータの数より少なくあってはなりません (...を含まない(C++20以降))。そうでなければ、プログラムは不正な形式です。識別子が関数表記でない場合、つまり、その後に括弧がない場合、全く置換されません。

#define ディレクティブのバージョン (2) は、単純な関数形式マクロを定義します。

#define ディレクティブのバージョン (3) は、可変個引数を持つ関数形式マクロを定義します。追加の引数 (可変引数と呼ばれます) は__VA_ARGS__識別子を使用してアクセスでき、これは置き換えられる識別子に供給される引数に置き換えられます。

#define ディレクティブのバージョン (4) は、可変個引数を持つ関数形式マクロを定義しますが、通常の引数はありません。引数 (可変引数と呼ばれます) は__VA_ARGS__識別子のみでアクセスでき、これは置き換えられる識別子に供給される引数に置き換えられます。

バージョン (3,4) の場合、置換リストにはトークンシーケンス__VA_OPT__(内容 )を含めることができます。これは、__VA_ARGS__が空でない場合は内容に置き換えられ、そうでなければ何も展開されません。

#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__)
F(a, b, c) // replaced by f(0, a, b, c)
F()        // replaced by f(0)
 
#define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__)
G(a, b, c) // replaced by f(0, a, b, c)
G(a, )     // replaced by f(0, a)
G(a)       // replaced by f(0, a)
 
#define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ })
SDEF(foo);       // replaced by S foo;
SDEF(bar, 1, 2); // replaced by S bar = { 1, 2 };
(C++20以降)

注:関数形式マクロの引数に、対応する左右の括弧のペアによって保護されていないコンマが含まれる場合 (テンプレート引数リストで最もよく見られます。例えばassert(std::is_same_v<int, int>);BOOST_FOREACH(std::pair<int, int> p, m)のように)、そのコンマはマクロ引数のセパレータとして解釈され、引数カウントの不一致によりコンパイルエラーが発生します。

[編集] スキャンと置換
  • スキャンは、置き換えたマクロを追跡します。スキャンがそのようなマクロと一致するテキストを見つけると、「無視する」とマークします(すべてのスキャンがそれを無視します)。これにより、再帰を防ぎます。
  • スキャンが関数形式マクロを見つけた場合、引数は置換リストに入れる前にスキャンされます。ただし、# および## 演算子はスキャンなしで引数を取ります。
  • マクロが置換された後、結果のテキストがスキャンされます。

擬似再帰マクロを定義できることに注意してください。

#define EMPTY
#define SCAN(x)     x
#define EXAMPLE_()  EXAMPLE
#define EXAMPLE(n)  EXAMPLE_ EMPTY()(n-1) (n)
EXAMPLE(5)
SCAN(EXAMPLE(5))

出力

EXAMPLE_ ()(5 -1) (5)
EXAMPLE_ ()(5 -1 -1) (5 -1) (5)

[編集] 予約済みマクロ名

標準ライブラリヘッダをインクルードする翻訳単位は、任意の標準ライブラリヘッダで宣言された名前を#defineまたは#undefすることはできません。

標準ライブラリのいかなる部分を使用する翻訳単位も、語彙的に同一な名前を#defineまたは#undefすることは許可されていません。

(C++11以降)

それ以外の場合、動作は未定義です。

[編集] # および ## 演算子

関数形式マクロでは、置換リスト内の識別子の前の#演算子は、識別子をパラメータ置換にかけて結果を引用符で囲み、実質的に文字列リテラルを作成します。さらに、プリプロセッサは、埋め込み文字列リテラルがある場合は、それを囲む引用符をエスケープするためにバックスラッシュを追加し、必要に応じて文字列内のバックスラッシュを二重にします。先頭と末尾のすべての空白は削除され、テキストの中央にある(ただし埋め込み文字列リテラル内ではない)空白のシーケンスは単一のスペースにまとめられます。この操作は「文字列化 (stringification)」と呼ばれます。文字列化の結果が有効な文字列リテラルでない場合、動作は未定義です。

#__VA_ARGS__の前に現れる場合、展開された__VA_ARGS__全体が引用符で囲まれます。

#define showlist(...) puts(#__VA_ARGS__)
showlist();            // expands to puts("")
showlist(1, "x", int); // expands to puts("1, \"x\", int")
(C++11以降)

置換リスト内の2つの連続する識別子の間の##演算子は、2つの識別子に対して(最初にマクロ展開されない)パラメータ置換を実行し、その結果を連結します。この操作は「連結 (concatenation)」または「トークン貼り付け (token pasting)」と呼ばれます。一緒に有効なトークンを形成するトークンのみが貼り付けられます。例えば、より長い識別子を形成する識別子、数値を形成する数字、または+=+=を形成するような演算子です。コメントは/*を貼り付けて作成することはできません。なぜなら、マクロ置換が考慮される前にコメントはテキストから削除されるためです。連結の結果が有効なトークンでない場合、動作は未定義です。

注:一部のコンパイラは、##をコンマの後ろ、__VA_ARGS__の前に置くことができる拡張機能を提供しています。この場合、可変引数が存在するときは##は何もしませんが、可変引数が存在しないときはコンマを削除します。これにより、fprintf (stderr, format, ##__VA_ARGS__)のようなマクロを定義することが可能になります。これは、__VA_OPT__を使用して標準的な方法でも実現できます。例えばfprintf (stderr, format __VA_OPT__(, ) __VA_ARGS__)のように。(C++20以降)

[編集] #undef ディレクティブ

#undef ディレクティブは識別子を未定義にします。つまり、#define ディレクティブによる識別子の以前の定義を取り消します。識別子に関連付けられたマクロがない場合、ディレクティブは無視されます。

[編集] 定義済みマクロ

以下のマクロ名は、すべての翻訳単位で定義済みです。

__cplusplus
使用されているC++標準のバージョンを示し、値に展開されます。
  • 199711L(C++11まで),
  • 201103L(C++11),
  • 201402L(C++14),
  • 201703L(C++17),
  • 202002L(C++20), または
  • 202302L(C++23)
    (マクロ定数)
__STDC_HOSTED__
(C++11)
実装がホスト型(OS上で動作)の場合、整数定数1に展開され、スタンドアロン型(OSなしで動作)の場合、0に展開されます。
(マクロ定数)
__FILE__
現在のファイル名を文字の文字列リテラルとして展開します。#lineディレクティブによって変更できます。
(マクロ定数)
__LINE__
現在の物理ソース行の行番号を整数定数として展開します。#lineディレクティブによって変更できます。
(マクロ定数)
__DATE__
翻訳の日付を"Mmm dd yyyy"形式の文字文字列リテラルとして展開します。"dd"の最初の文字は、月の日が10未満の場合、スペースになります。月の名前はstd::asctime()によって生成されるかのようです。
(マクロ定数)
__TIME__
翻訳時刻を"hh:mm:ss"形式の文字文字列リテラルとして展開します。
(マクロ定数)
__STDCPP_DEFAULT_NEW_ALIGNMENT__
(C++17)
値がアライメント非対応のoperator newの呼び出しによって保証されるアライメントであるstd::size_tリテラルに展開されます(より大きなアライメントは、operator new(std::size_t, std::align_val_t)のようなアライメント対応のオーバーロードに渡されます)。
(マクロ定数)
__STDCPP_­BFLOAT16_­T____STDCPP_­FLOAT16_­T____STDCPP_FLOAT32_T____STDCPP_FLOAT64_T____STDCPP_FLOAT128_T__
(C++23)
実装が対応する拡張浮動小数点型をサポートする場合に限り、1に展開されます。
(マクロ定数)

以下の追加マクロ名は、実装によって定義される場合があります。

__STDC__
実装定義の値。存在する場合、通常C適合性を示すために使用されます。
(マクロ定数)
__STDC_VERSION__
(C++11)
実装定義の値。存在する場合。
(マクロ定数)
__STDC_ISO_10646__
(C++11)

wchar_tがUnicodeを使用する場合、yyyymmL形式の整数定数に展開されます。日付はサポートされているUnicodeの最新のリビジョンを示します。

(C++23まで)

実装定義の値。存在する場合。

(C++23から)

(マクロ定数)
__STDC_MB_MIGHT_NEQ_WC__
(C++11)
基本文字セットのメンバー(例えばwchar_tにUnicodeを使用するEBCDICベースのシステムなど)に対して'x' == L'x'がfalseになる可能性がある場合、1に展開されます。
(マクロ定数)
__STDCPP_THREADS__
(C++11)
プログラムが複数の実行スレッドを持つことができる場合、1に展開されます。
(マクロ定数)
__STDCPP_STRICT_POINTER_SAFETY__
(C++11)(C++23で削除)
実装が厳格なstd::pointer_safetyを持つ場合、1に展開されます。
(マクロ定数)

これらのマクロの値(__FILE____LINE__を除く)は、翻訳単位全体で一定のままです。これらのマクロを再定義または未定義しようとすると、未定義の動作になります。

言語機能テストマクロ

標準では、C++11以降で導入されたC++言語機能に対応するプリプロセッサマクロのセットが定義されています。これらは、当該機能の存在を検出するためのシンプルで移植性の高い方法を意図しています。

詳細については、機能テストを参照してください。

(C++20以降)


注釈

関数ローカルな定義済み変数__func__は定義済みマクロではありませんが、通常は__FILE____LINE__とともに、例えばassertなどで使用されます。

(C++11以降)

[編集]

#include <iostream>
 
// Make function factory and use it
#define FUNCTION(name, a) int fun_##name() { return a; }
 
FUNCTION(abcd, 12)
FUNCTION(fff, 2)
FUNCTION(qqq, 23)
 
#undef FUNCTION
#define FUNCTION 34
#define OUTPUT(a) std::cout << "output: " #a << '\n'
 
// Using a macro in the definition of a later macro
#define WORD "Hello "
#define OUTER(...) WORD #__VA_ARGS__
 
int main()
{
    std::cout << "abcd: " << fun_abcd() << '\n';
    std::cout << "fff: " << fun_fff() << '\n';
    std::cout << "qqq: " << fun_qqq() << '\n';
 
    std::cout << FUNCTION << '\n';
    OUTPUT(million); //note the lack of quotes
 
    std::cout << OUTER(World) << '\n';
    std::cout << OUTER(WORD World) << '\n';
}

出力

abcd: 12
fff: 2
qqq: 23
34
output: million
Hello World
Hello WORD World

[編集] 欠陥報告

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
CWG 2908 C++98 __LINE__が現在の
物理行番号に展開されるのか、論理行番号に展開されるのか不明であった。
現在の
物理行番号に展開されます
LWG 294 C++98 標準ライブラリヘッダをインクルードする翻訳単位は、
他の標準ライブラリヘッダで宣言された名前を定義するマクロを含みうる
禁止された
P2621R2 C++23 ユニバーサル文字名が許可されていなかった
トークン連結によって形成されること
許可

[編集] 関連項目

C++ドキュメントマクロシンボルインデックス
テキストマクロの置換に関するC言語ドキュメント
English 日本語 中文(简体) 中文(繁體)