【初心者C++er Advent Calendar 2016 21日目】C++ でプリプロセスマクロを使う場面
初心者C++er Advent Calendar 2016 21日目の記事です。
さて、巷ではマクロを使用したコードを公開すると『static const
を使え』や『typedef
しろ』、『関数テンプレートでおk』などと斧が飛んでくる突っ込まれることが多いです。
これは C++ では『基本的にはマクロを使うべきではなく』さらに『マクロを使わないでよいコード』に直せることが多いからです。
では逆に『マクロを使うべきコード』というのはどういうものなのでしょうか。
この記事では『マクロを使うべきコード』の実例をいくつか紹介してみたいと思います。
[インクルードガード]
ヘッダーファイルを記述する際に『重複インクルードを防止するため』にインクルードガードという技法が使用されれます。
これは #ifndef
を利用して『一度だけヘッダーファイルが読み込まれる』ような仕組みです。
// hoge.h #ifndef HOGE_H #define HOGE_H // ここに実装を記述する #endif // HOGE_H
これにより複数回 #include "hoge.h"
しても一度だけ定義が読み込まれます。
ただ、最近は同等の機能である #pragma once
を実装してるコンパイラもあるので、そちらを使用している人もいます。
[キーワードなどを置き換える]
さて、次のように constexpr
を使ったコードがあるとします。
constexpr auto plus(int a, int b){ return a + b; } constexpr auto minus(int a, int b){ return a - b; } static_assert(plus(1, 2) == 3, ""); static_assert(minus(4, 5) == -1, "");
これは C++11 に対応してるコンパイラであれば問題なく動作します。
しかし、環境によってはどうしても C++03 に対応しなければならないこともあります。
こういう場合、constexpr
というキーワードをマクロに置き換えることで、複数の環境に柔軟に対応する事が出来ます。
// C++11 以上ならば #if __cplusplus >= 201103L // constexpr をマクロに置き換える #define CONSTEXPR constexpr #else // C++11 以上に対応してないなら空のマクロを定義 #define CONSTEXPR #endif // constexpr をマクロに置き換える CONSTEXPR int plus(int a, int b){ return a + b; } CONSTEXPR int minus(int a, int b){ return a - b; } #if __cplusplus >= 201103L static_assert(plus(1, 2) == 3, ""); static_assert(minus(4, 5) == -1, ""); #endif
このように『マクロ以外』で置き換えることが出来ないようなワークアラウンドに対応する場合に利用できます。
[コンパイルするときに挙動を変更したい場合]
例えば、次のように『デバッグコードを仕込んだコード』があるとします。
int plus(int a, int b){ // DEBUG が定義されている時のみログを出力したい #ifndef DEBUG std::cout << a << std::endl; std::cout << b << std::endl; #endif return a + b; }
このように『マクロを使用すること』でコンパイル時に『挙動を変更する』事が出来ます
# DEBUG マクロを定義してコンパイルする $ g++ main.cpp -DDEBUG $ ./a 1 2 3
gcc だとこんな感じでコンパイル時にマクロを定義する事が出来ます。
[まとめ]
と、言う感じでパッと思いついたものを上げてみました。
他にも使うべき場面はありますが、初心者向けならこのあたりでしょうか。
C++ では『マクロを使うべきではないコード』もたくさんありますが『マクロでしか実装出来ないコード』もまた存在します。
マクロは用法・用量を守って正しくお使いください。