bool 型の変数を嫌う

2020年1月18日

C++ では標準で bool 型がサポートされるようになりました。組み込み業界ではいまだ C が多く使われるので、次のようなコードを目にする機会も多いことでしょう。

#define FALSE 0
#define TRUE  1

その意味で、bool は素晴らしいものです。どんどん置き換えて、int との混在を防ぐべきです。

しかし、少し立ち止まって、「本当に bool でなければならないのか?」と考えるべき場面も実はあるのです。

enum を使う

結論から言うと、bool 型の変数を使おうとする場面では常に、「enum と比べてどちらが読みやすいか」ということを念頭に置くとよいでしょう。ここでは、enum のほうが適していると思われる2つのケースを提唱します。

引数になる場合

関数の引数に bool が来ることほど読み手を惑わすものはありません。次のコードは、ポート出力の負論理・正論理を、コンストラクタで決定できるように作られたクラスです。

class PortOutput
{
private:
  const bool m_isNegative;  // 負論理なら true
public:
  PortOutput(int num, bool isNegative);
};

ここまではいいのです。問題は、このクラスを使ってインスタンスを生成しようとするコード側にあります。

PortOutput g_port0(0, false);
PortOutput g_port1(1, true);
PortOutput g_port2(2, false);
PortOutput g_port3(3, false);

このコードを読んだ人は、ここにある false や true が何を意味するのか想像することもできません。そこで元のコードを読みに行けばまだいいほうで、最悪の場合、「逆の意味に思い込む」ということもあるのです(実際にありました)。

ここで enum を導入すれば、次のようになります。

enum Logic
{
  eNegative,
  ePositive,
};

class PortOutput
{
private:
  const Logic m_logic;
public:
  PortOutput(int num, Logic logic);
};

PortOutput g_port0(0, ePositive);
PortOutput g_port1(1, eNegative);
PortOutput g_port2(2, ePositive);
PortOutput g_port3(3, ePositive);

コードに語らせるとは、まさにこのことです。

主語がクラス自身でない場合

値の上下限を管理するためのクラスがあり、ユーザーはそれを動的に無効化・有効化したいとします。焦点を絞るため省略して書きますが、コードはおおむね次のようになります。

class Limiter
{
private:
  bool m_isEnabled;

public:
  void disable() { m_isEnabled = false; }
  void enable()  { m_isEnabled = true;  }
};

ここまでなら特段問題のない、よくあるコードです。ここで、無効化・有効化の設定を、下限・上限それぞれ「個別に」行いたいと要望されたとしたら、どうなるでしょうか。

class Limiter
{
private:
  bool m_isEnabledLower;
  bool m_isEnabledUpper;

public:
  void disableLower() { m_isEnabledLower = false; }
  void enableLower()  { m_isEnabledLower = true;  }
  void disableUpper() { m_isEnabledUpper = false; }
  void enableUpper()  { m_isEnabledUpper = true;  }
};

動くには動きます。しかし、私はこの isEnabledLower という表現に違和感を覚えずにいられません。自然な英語表現から逸脱してしまっているからです。しかも長い。

その理由は、実はこのとき isEnabled の主語が「リミッタ」から「下限」にレベルダウンしているからです。主語がクラス自身でない bool 型のメンバ変数は、おのずと命名が難しくなるものです。

そこで enum の出番です。

enum Effect
{
  eDisabled,
  eEnabled,
};

class Limiter
{
private:
  Effect m_lower;
  Effect m_upper;

public:
  void disableLower() { m_lower = eDisabled; }
  void enableLower()  { m_lower = eEnabled;  }
  void disableUpper() { m_upper = eDisabled; }
  void enableUpper()  { m_upper = eEnabled;  }
};

短くなっただけでなく、流れるように読めるコードになりました。

enum は、デバッガのウォッチ画面でもわかりやすいという効果があります。ぜひ、検討の選択肢に入れてみてください。