Code Fix

中級

error: call of overloaded '...' is ambiguous の原因と直し方

同じ名前の関数が複数のオーバーロードを持ち、渡した引数の型からどちらを呼ぶべきかコンパイラが一意に決められないときに出るエラーです。

エラーメッセージの読み方

main.cpp:5:9: error: call of overloaded 'show(int)' is ambiguous
main.cpp
ファイル名
5
行番号
9
列番号 — この位置でg++が構文解析に失敗しました
call of overloaded 'show(int)' is ambiguous
内容 — 期待していたもの、または受け付けられなかったもの

このエラーが出る典型パターン

パターン1

 1  #include <iostream>
 2  void show(long x) { std::cout << "long:" << x << std::endl; }
 3  void show(unsigned long x) { std::cout << "unsigned long:" << x << std::endl; }
 4  int main() {
 5      show(5  );
              ^
 6      return 0;
 7  }
main.cpp:5:9: error: call of overloaded 'show(int)' is ambiguous

int型の5をlongに変換するかunsigned longに変換するかは同じ変換ランクで並んでしまい、コンパイラはどちらか一方を優先できません。リテラルにLを付けて型を明示します。

直し方: 5 を 5L にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  #include <iostream>
 2  void report(long x) { std::cout << "long:" << x << std::endl; }
 3  void report(unsigned long x) { std::cout << "unsigned long:" << x << std::endl; }
 4  int main() {
 5      report(10  );
                 ^
 6      return 0;
 7  }
main.cpp:5:11: error: call of overloaded 'report(int)' is ambiguous

「型が近ければコンパイラがうまく選んでくれる」というのは誤解です。曖昧な場合はエラーとして人間の判断に委ねられます。

直し方: 10 を 10L にします。

この問題を解いてみる →

パターン3

 1  #include <iostream>
 2  void log_(long x) { std::cout << "long:" << x << std::endl; }
 3  void log_(unsigned long x) { std::cout << "unsigned long:" << x << std::endl; }
 4  int main() {
 5      log_(1  );
              ^
 6      return 0;
 7  }
main.cpp:5:9: error: call of overloaded 'log_(int)' is ambiguous

Lサフィックスを付けてリテラルの型そのものをlongにしてしまえば、変換の必要が無くなり曖昧さが解消します。

直し方: 1 を 1L にします。

この問題を解いてみる →

パターン4

 1  #include <iostream>
 2  void display(long x) { std::cout << "long:" << x << std::endl; }
 3  void display(unsigned long x) { std::cout << "unsigned long:" << x << std::endl; }
 4  int main() {
 5      display(3  );
                 ^
 6      return 0;
 7  }
main.cpp:5:12: error: call of overloaded 'display(int)' is ambiguous

int型のリテラルをlongにするかunsigned longにするかで優先順位が付かず、呼び出しが曖昧になります。

直し方: 3 を 3L にします。

この問題を解いてみる →

パターン5

 1  #include <iostream>
 2  void trace(long x) { std::cout << "long:" << x << std::endl; }
 3  void trace(unsigned long x) { std::cout << "unsigned long:" << x << std::endl; }
 4  int main() {
 5      trace(9  );
               ^
 6      return 0;
 7  }
main.cpp:5:10: error: call of overloaded 'trace(int)' is ambiguous

リテラルにLサフィックスを付けて型を明示すれば、変換の曖昧さが解消します。

直し方: 9 を 9L にします。

この問題を解いてみる →

よくある誤解

「型が近ければコンパイラがうまく選んでくれる」というのは誤解です。C++のオーバーロード解決は複数の候補が同じ変換ランクで並んだ場合、どちらか片方を勝手に選ぶのではなく、エラーとして人間に判断を委ねます。

実務での勘所

曖昧になる典型例は、f(int)とf(double)の両方がある状態でf(1.0f)(float型の引数)を呼んだ場合です。floatからdoubleへの変換(浮動小数点昇格)と、floatからintへの変換(浮動小数点から整数への変換)は、C++のオーバーロード解決の規則上どちらも同じ順位の「標準変換」とみなされ、片方が明確に優れているとは判定されません。同じ順位の候補が複数残った時点で、コンパイラは推測で決めることを拒否し、人間に明示的なキャストで意図を示すよう求めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)