C++の定義済みマクロを見てみる
案外知らない定義済みマクロ、ちょっと覗いてみようじゃないか。
はじめに
フレームワークや大規模システムのコードを見てみると、定義済みマクロが結構使われてたりします。
「うわかっけぇ~!」となっても、いつもそこで終わってしまうので、ちょっとは知識をつけておこうかなと。
この記事では、見ていた中で面白そうなものをいくつかピックアップして、軽く紹介します。
環境
- Windows11
- g++ 14.2.0
- C++20
紹介
__PRETTY_FUNCTION__
現在実行されている関数を取得する。
関数名だけでなく、引数や戻り値の型、所属するクラスなども取得できる。
これは明らかに便利ですね!デバッグ環境が乏しいときでも効率的にできます。
#include <iostream>
#include <string>
void hoge(int arg) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
return;
}
class Fuga {
public:
static void fuga(void) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
hoge(67);
auto piyo = [](std::string str) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
};
Fuga::fuga();
piyo("fuga!");
return 0;
}
実行結果
int main()
void hoge(int)
static void Fuga::fuga()
main()::<lambda(std::string)>
__TIMESTAMP__
そのソースファイルが最後に更新された日時を取得する。
Gitなどでバージョン管理しないとき、簡易的な管理として使えそうです。
#include <iostream>
int main() {
std::cout << __TIMESTAMP__ << std::endl;
return 0;
}
実行結果
Wed Dec 31 23:23:37 2025
__COUNTER__
これが登場するたびに値が0から1ずつインクリメントされる。
トークン連結演算子##と組み合わせて、衝突しない変数名を生成することができる。
例えば、コンストラクタで測定を開始し、デクストラクタで測定を終了する変数を考えてみる。
同一のスコープでこの変数を2つ作りたいとき、ユーザーは本来であれば変数名が衝突しないように気をつける必要がある。
しかし、以下のコードのようにすれば、衝突しない変数名を避けることができ、簡易的な時間計測が可能になる。
#include <iostream>
#include <chrono>
#include <thread>
// 一意の変数名を生成する
#define CONCAT_IMPL(x, y) x##y
#define CONCAT(x, y) CONCAT_IMPL(x, y)
#define ANONYMOUS_VARIABLE(prefix) CONCAT(prefix, __COUNTER__)
// コンストラクタで測定開始
// デクストラクタで測定終了
class ScopeTimer {
public:
explicit ScopeTimer(const char* name)
: name_(name),
start_(std::chrono::steady_clock::now()) {
std::cout << "[Start] " << name_ << std::endl;
}
~ScopeTimer() {
auto end = std::chrono::steady_clock::now();
auto duration = end - start_;
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
std::cout << "[End] " << name_ << " (" << ms << " ms)" << std::endl;
}
private:
const char* name_;
std::chrono::time_point<std::chrono::steady_clock> start_;
};
// 時間計測する変数を生成する
#define MEASURE_SCOPE(name) \
ScopeTimer ANONYMOUS_VARIABLE(timer_)(name)
int main() {
MEASURE_SCOPE("Heavy Process 1");
std::this_thread::sleep_for(std::chrono::milliseconds(200));
MEASURE_SCOPE("Heavy Process 2");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
実行結果
[Start] Heavy Process 1
[Start] Heavy Process 2
[End] Heavy Process 2 (109 ms)
[End] Heavy Process 1 (322 ms)
おわりに
まだまだ他にも色々ありますが、ひとまず今回はここまで。
調べてみると、結構使えそうなものがあるんですね~!
ちなみにこの記事、大晦日の23:58に書き終わりました!
良いお年を!