定数定義
定数を定義する方法の一つとして#defineを使う方法がある。
#define kSomeConstant 1.23
しかし、#defineだとプリプロセッサによってコンパイル前にシンボルkSomeConstantはすべて1.23に置換されてしまう。したがって、
- コンパイルエラー時に1.23という値が使われkSomeConstantであることを知るのが困難
- デバッグ時にシンボル名がわからない
というデメリットがある。そのため、
static const double kSomeConstant = 1.23;
とすることで、言語で規定された定数となりコンパイラから見えることになる。
なお、クラスのメンバ変数として定数を定義する際は
class A{ public: A() { std::cout << kConst << std::endl; } private: static const int kConst = 1; };
とヘッダ内に書く。以前は宣言時に初期化することができなかったため古いコンパイラではエラーになる。その時はソースファイル中で定義を行う必要がある。
enumハック
言語仕様上、constな変数のアドレスを使うことが許されておりそれを禁止したい時にはenumとして定義
enum{ kConst = 1 };
するとよい。また、テンプレートを用いたメタプログラミングの基本テクニックとしても利用されている。
インライン関数
関数呼び出しのオーバーヘッドをなくす手段として#defineを使ったマクロが知られているが、数々の問題を誘引するため避けるべきである。例えば、大きい値を返すマクロ
#define max(a, b) [1]a) > (b) ? (a) : (b
はコンパイルも通るが
max(++a, b)
とするとaが何回インクリメントされるかはa, bの値に依存して変わるという悩ましい挙動をする。(a=5, b=0とa=5, b=10では挙動が異なる。)
解決策としてinline関数のテンプレートを作ることで、効率的で振る舞いが明白かつ型安全にできる。
template<typename T> inline T max_val(const T a, const T b){ return a > b ? a : b; }
参考文献
Effective C++ 第3版, スコット・メイヤーズ著
脚注
↑1 | a) > (b) ? (a) : (b |
---|