【C++】reference to 'x' is ambiguous エラーの対処【call to '' is ambiguous】

usingディレクティブを用いたコードで、次のようなエラーが発生してしまうことがある。

using namespace std;

struct string {};
string s; // error: reference to 'string' is ambiguous

template<class T> T max(T a, T b) { return a > b ? a : b; }
int v = max(1, 2); // error: call to 'max' is ambiguous

原因は、独自に宣言したstringクラスやmax関数が名前空間std内で既に宣言されているためである。スコープ解決演算子(::)を用いてグローバルスコープ側の機能名と名前空間内の機能名を区別する必要がある。

using namespace std;
struct string {};
::string s;    // OK: グローバルスコープ側のstringクラス
std::string t; // OK: 名前空間std側のstringクラス

template<class T> T max(T a, T b) { return a > b ? a : b; }
int v = ::max(1, 2);    // OK
int w = std::max(1, 2); // OK

改修箇所が多くなる場合は、using宣言を用いて一括で名前解決するのも良いだろう。

using namespace std;
struct string {};

namespace ns {
  using ::string;
  void g() { string s; } // グローバルスコープ側のstringクラス
  void f() { string s; } // グローバルスコープ側のstringクラス
  void h() {
    using std::string;
    string s; // 名前空間std側のstringクラス
  }
}

struct T {
  // クラススコープではusing宣言が行えない
  using std::string; // error: using declaration in class refers into 'std::', which is not a class
  using string = std::string; // OK(エイリアス宣言で対処)
};

同等のエラーは関数やテンプレートクラス、クラスオブジェクトとの競合によっても発生する。

using namespace std;

int plus(int a, int b) { return a + b; }

int main() {
  int v = plus(1, 2); // error: reference to 'plus' is ambiguous

  int v = ::plus(1, 2); // OK(名前空間を明示する)
  
  using ::plus;
  int w = plus(1, 2);   // OK(using宣言を行う)
}

関数同士の競合が発生した場合はcall to 'x' is ambiguousという異なるエラーメッセージになるが、エラーの趣旨や対処方法は変わらない。

using namespace std;
template<class T> T max(T a, T b) { return a > b ? a : b; }
int v = max(1, 2);   // error: Call to 'max' is ambiguous
int v = ::max(1, 2); // OK

ちなみに、インライン名前空間を用いた場合も、今回と同様の問題が発生する場合があるため注意したい。

namespace A {
  inline namespace B {
    struct X {};
  }
  struct X : B::X {};
}
A::B::X x; // OK
A::X    y; // error: reference to 'X' is ambiguous

なお、もっとも賢明な対策はusing namespace std;によるusingディレクティブを用いないようにすることである。

using namespace std; の危険性と注意点・代替案

広告

広告