2017-03-03 5 views
10

は、このクラスを検討:このメンバー関数への呼び出しがあいまいなのはなぜですか?

class Base{ 
public: 
    void func(double a) = delete; 
    void func(int a) const {} 
}; 

int main(){ 
    Base base; 

    base.func(1); 
    return 0; 
} 

、それは次のエラー生成++打ち鳴らすを使用してコンパイルする場合:++ gの

clang++ --std=c++11 test.cpp 
test.cpp:22:7: error: call to member function 'func' is ambiguous 
    base.func(1); 

を、警告が生成される:

g++ -std=c++11 test.cpp 
test.cpp: In function ‘int main()’: 
test.cpp:22:13: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: base.func(1); 

なぜこのコードでありますあいまいですか?

+0

整数は浮動小数点型に簡単に変換できます。 'func(int)'が最適なマッチですが、 'func(double)'は依然として実行可能な選択肢であり、呼び出しが曖昧になります。 –

+2

constメンバ関数と非constメンバ関数を含む複雑なロジックに慣れているようです。 FWIWでは、 'func(double)'を 'const'メンバ関数に変更することで問題が取り除かれます。 –

答えて

10

非静的メンバ関数:暗黙を組み込んだ後

Overload resolution is a mechanism for selecting the best function to call given a list of expressions that are to be the arguments of the call and a set of candidate functions that can be called based on the context of the call. The selection criteria for the best function are the number of arguments, how well the arguments match the parameter-type-list of the candidate function, how well (for non-static member functions) the object matches the implicit object parameter, and certain other properties of the candidate function.

void func(double); // #1 
void func(int) const; // #2 

また他の引数として、オーバーロード解決([over.match]/p1)であると考えられるimplicit object parameterを受け入れますオブジェクトのパラメータをメンバ関数のシグネチャに追加すると、コンパイラは2つのオーバーロードを認識します。

void func(Base&, double); // #1 
void func(const Base&, int); // #2 

、コールに基づいて最適な実行可能な機能を選択しようとします:(タイプBaseの非const左辺値である)baseからBase&への変換は、直接(完全に一致ランクを持っている

Base base; 
base.func(1); 

を参照結合はIdentity conversionを生じる) - Table 13を参照のこと。二番目のパラメータ、doubleに不可欠prvalue 1からの変換のための今すぐ

— S1 and S2 are reference bindings ([dcl.init.ref]), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers. [ Example:

int f(const int &); 
int f(int &); 
int g(const int &); 
int g(int); 

int i; 
int j = f(i); // calls f(int &) 
int k = g(i); // ambiguous 

baseからconst Base&への変換は完全一致でもあるランクは、しかし、[over.ics.rank]/p3.2.6は、より良い変換シーケンスを持っている#1を宣言します浮動積分変換[conv.fpint])です。変換ランクです。一方、1~intは、のID変換であり、完全一致ランクです。この引数には、考えられている#2がより良い変換シーケンス([over.ics.rank]/p3.2.2)持っている:

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

— for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that, [...]

— the rank of S1 is better than the rank of S2, or S1 and S2 have the same rank and are distinguishable by the rules in the paragraph below, or, if not that, [...]

オーバーロードの解決成功するための変換シーケンスが異なるために最大で1つのパラメータ([over.match.best])が存在することが必要です

ここで、ICS は(#1)〜(#2)ICS よりも優れているが、今度は、ICS は(#2)ICSよりも優れて(#1)であるため、コンパイラは2つのオーバーロードを選択できず、あいまいさを検出します。

+0

私はちょうど同様の回答を投稿したかった。一つの違い:なぜあなたは 'Base *'を書いていますか? 13.3.1.4は、暗黙的なオブジェクトパラメータが "cv Xへの左辺参照"であるため、 'Base&'と言います。 –

+0

優れた答え。単純にちょっとしたニックピッキングもあります。 'const base&'は 'base'型の引数に直接バインドするので、対応する暗黙の変換シーケンスも恒等変換です。資格の変換はありません。あなたが引用した箇条書きの条件が満たされているので、もう一方の変換(「ベース&」への変換)が良くなります。 – bogdan

+0

@bogdan私はこの部分については分かりませんでした。とても感謝しています。 –

0

関数がオーバーロードされると、オーバーロードの解決が最初に行われます。削除された機能が最もよく一致して選択されている場合、プログラムは不正な形式になります。

が二重にint型から暗黙的な変換であり、コンパイラはあなたがコールする予定の機能を知りませんので、したがって、あなたのプログラムは、次のように同じエラーを生成します:

class Base{ 
public: 
    void func(double a) {} 
    void func(int a) const {} 
}; 
+3

あなたの説明が欠けています:はい暗黙の変換 'int'->' double'がありますが、 'int'は引数の完全一致です。最後のキーは 'const' – bolov

-1

それはのためにconst修飾子はfunc(int)です。 baseインスタンスはconstではありません。インスタンスがconstでない場合、C++コンパイラはnon-constメソッドを最初に見つけたようです。そしてコンパイラはそのメソッドが削除されていることを発見しました。コンパイラは警告を出します。

const修飾子を削除するか、またはconst修飾子をfunc(double)に移動して、警告を取り除こうとします。

この警告は暗黙の変換に関するものではありません。 によってfuncを呼び出しても、どちらかといえば良いことではありません。 2のような

+1

で間違っています。最初に最初の方法が見つかりません。 2つはあいまいです。 – bolov

関連する問題