メモの日々


2016年04月06日(水) [長年日記]

[c++] C++で型名と変数名を同じにしてみる

C++で型名と変数名を同じにしたいときにどうするか。

サンプルコード

次のように、クラスouter内にinnerと言う名前のクラスとメンバ変数を両方定義してみる。

#include <iostream>

struct outer {
  struct inner {
    void f() { std::cout << "hello" << std::endl; }
  };

  inner inner;
};

int main() {
  outer::inner a;
  a.f();
}

このコードはコンパイルエラーになる(g++ 4.8.5を使用)。main()内の「outer::inner」はクラス名ではなくメンバ変数名と解釈される。

次のように struct を補うとコンパイルできるようになる。

int main() {
  struct outer::inner a;
  a.f();
}

別名を使う

struct outer::inner は長いので、エイリアス宣言を使って別名を定義してみる。

int main() {
  using in = struct outer::inner;
  in a;
  a.f();
}

このコードは動作するが、g++は

warning: declaration 'struct outer::inner' does not declare anything [enabled by default]

という警告を出力する。とはいえ、structを省いて「using in = outer::inner;」と書くとコンパイルできない。警告が出るのはg++のバグである気がする。clangを使うと警告は出力されない。

試しにstructの代わりに「using in = typename outer::inner;」とtypenameを書いてみたら、g++ではコンパイルできた。しかし、clangではコンパイルエラーになる。この書き方は不正なのだろうと思われる。

g++でもclangでも警告なしにコンパイルするには、エイリアス宣言ではなくtypedefを使えばよい。

int main() {
  typedef struct outer::inner in;
  in a;
  a.f();
}