web-dev-qa-db-ja.com

リテラル `0`がintおよびconst string&オーバーロードの有効な候補であるため、あいまいな呼び出しが発生します

最近バグを修正しました。

次のコードでは、オーバーロードされた関数の1つがconstで、もう1つはそうではありませんでした。この問題は、両方の関数をconstにすることで修正されます。

私の質問は、コンパイラーがパラメーターが0のときにのみ不平を言った理由です。

#include <iostream>
#include <string>

class CppSyntaxA
{
public:
    void f(int i = 0) const { i++; }
    void f(const std::string&){}
};

int main()
{
    CppSyntaxA a;
    a.f(1);  // OK
    //a.f(0);  //error C2666: 'CppSyntaxA::f': 2 overloads have similar conversions
    return 0;
}
44
Cong Ma

_0_はC++では特別です。 nullポインターの値は_0_であるため、C++では_0_をポインター型に変換できます。つまり、あなたが電話したとき

_a.f(0);
_

_0_の値でintを指定してvoid f(int i = 0) constを呼び出すか、_char*_をnullに初期化してvoid f(const std::string&)を呼び出すことができます。

通常、intバージョンは完全に一致するのでより良いでしょうが、この場合intバージョンはconstなので、「変換」する必要がありますa _const CppSyntaxA_に変換します。ここで、_std::string_バージョンはそのような変換を必要としませんが、_char*_への変換とその後の_std::string_への変換が必要です。これは、どちらの場合も、変換が等しいと見なすのに十分であると見なされ、あいまいです。両方の関数をconstまたは非constにすることで問題が修正され、intオーバーロードが選択されます。

56
NathanOliver

私の質問は、コンパイラーがパラメーターが0のときにのみ不平を言った理由です。

0は整数リテラルであるだけでなく、nullポインタリテラルでもあるからです。 1はnullポインターリテラルではないため、あいまいさはありません。

あいまいさは、文字へのポインターを引数として受け入れるstd::stringの暗黙的な変換コンストラクターから発生します。

さて、intからintへのID変換は、ポインタから文字列への変換よりも優先されますが、変換を含む別の引数があります。暗黙のオブジェクト引数です。 1つのケースでは、変換はCppSyntaxA&からCppSyntaxA&への変換であり、別のケースではCppSyntaxA&からconst CppSyntaxA&への変換です。

したがって、1つの引数のために1つのオーバーロードが優先され、別の引数のためにもう1つのオーバーロードが優先されます。したがって、明確に優先されるオーバーロードはありません。

この問題は、両方の関数をconstにすることで修正されます。

両方のオーバーロードがconst修飾されている場合、暗黙のオブジェクト引数変換シーケンスは同一であるため、オーバーロードの1つが明白に優先されます。

11
eerorika