#2 #define よりも const, enum, inline を使おう

ちょっともう少し C++ をきちんと理解しないといけないな...と思うことがあり,ロボットも終わったちょうどいいタイミングなので,毎日少しづつ Effective C++ を読んで行くことにしました.ただ,読むだけだとどうも頭に入ってこないので,できるだけブログにアウトプットしようかと.あんまりまんまブログに上げてしまうと「著作権的にどうなの?」という話になってしまうので,自分なりに言い換えて,サンプルコードを書いてアップすることにしました.

ということで,今日が Day1 です!いつまで続くか見ものですが(笑)

1. int, bool, char の定数関しては,宣言時に値を代入し,定義なしで使うことができるが,それ以外は定義が必要.

該当コードは下記の部分になります,int, char, bool に関しては静的定数ならば宣言時の代入が許されてます.クラスのメンバとして配列を持たせたい時に,以前だと #define で定数を宣言していたと思うんですが,この仕組みを使えば const 変数で配列サイズを定義できます.
ただ,これって,なんで double とか float はダメなんですかね.これができたほうが見通しが良くなる気がするんですが.

class Sample {
private:

  static const bool BOOL_NUM=true;
  static const int INT_NUM=5;
  static const unsigned char CHAR_NUM=2;

  // Can not assign value in declaration.
  static const float FLOAT_NUM;
  static const double DOUBLE_CONST;

  int arr[INT_NUM];
};

const double Sample::DOUBLE_CONST=2.0;
const float Sample::FLOAT_NUM=3.0;
2. できるだけ #define の使用を避けて,const を使う.配列のサイズ指定に使いたいときは,int 定数への宣言時値代入を使うことができる.コンパイラによって,この方法が取れない場合,enumハックを使えばOK.

どうやらコンパイラによっては1のやり方が怒られる場合もあるようで,その場合は enum ハックというテクニックを使えばいいようです.

class Sample {
private:
  enum {ENUM_NUM=10};
  int arr2[ENUM_NUM];
};
3. マクロの使用をできるだけ避けて,インライン関数を使う.

マクロって結局はほぼ文字列の置き換えみたいな部分があると思うので,表現がちょっと複雑になると,意図しない使われ方をされたときに全然使い物にならなくなってしまうんですよね.例えば,下記の関数だと,マクロ内部で a のインクリメントが二回実行されてしまうので,マクロのMAXを呼んだ場合は,期待値としては 4 であるにもかかわらず,5になってしまいます.

#define MAX(a, b) ((a) > (b) ? (a) : (b))

template<typename T>
inline double max(const T &a, const T &b) {
  return ((a) > (b) ? (a) : (b));
}

int main(int, char**) {

  int a = 3.0;
  int b = 3.0;
  
  std::cout << "Before Calling : " << a << std::endl;
  std::cout << MAX(++a, b) << std::endl;
  std::cout << "After Calling  : " << a << std::endl;
  std::cout << std::endl;

  int x = 3.0;
  int y = 3.0;
  
  std::cout << "Before Calling : " << x << std::endl;
  std::cout << max(++x, y) << std::endl;
  std::cout << "After Calling  : " << x << std::endl;

  return 0;

}
4. 本日のサンプルコード
#include <iostream>

#define DEFINE_NUM 10

#define MAX(a, b) ((a) > (b) ? (a) : (b))

template<typename T>
inline double max(const T &a, const T &b) {
  return ((a) > (b) ? (a) : (b));
}

class Sample {
private:

  enum {ENUM_NUM=10};
//  enum {DEFINE_NUM=20};

  // Can assigne value in declaration.
  static const bool BOOL_NUM=true;
  static const int INT_NUM=5;
  static const unsigned char CHAR_NUM=2;

  // Can not assign value in declaration.
  static const float FLOAT_NUM;
  static const double DOUBLE_CONST;
  int arr[INT_NUM];
  int arr2[ENUM_NUM];
  int arr3[DEFINE_NUM];
};

const double Sample::DOUBLE_CONST=2.0;
const float Sample::FLOAT_NUM=3.0;

int main(int, char**) {
  std::cout << "Effective CPP #2" << std::endl;

  int a = 3.0;
  int b = 3.0;
  
  std::cout << "Before Calling : " << a << std::endl;
  std::cout << MAX(++a, b) << std::endl;
  std::cout << "After Calling  : " << a << std::endl;
  std::cout << std::endl;

  int x = 3.0;
  int y = 3.0;
  
  std::cout << "Before Calling : " << x << std::endl;
  std::cout << max(++x, y) << std::endl;
  std::cout << "After Calling  : " << x << std::endl;

  return 0;
}

参考文献

Effective C++ 第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTI)

Effective C++ 第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTI)