C ++追加過負荷のあいまいさ
-
25-09-2019 - |
質問
私はコードベースで厄介な難問に反対しています。私のコードがこのエラーを生成する理由はまったくわかりませんが、(たとえば)STD :: Stringはそうではありません。
class String {
public:
String(const char*str);
friend String operator+ ( const String& lval, const char *rval );
friend String operator+ ( const char *lval, const String& rval );
String operator+ ( const String& rval );
};
これらの実装は、自分で想像するのに十分簡単です。
私のドライバープログラムには、次のものが含まれています。
String result, lval("left side "), rval("of string");
char lv[] = "right side ", rv[] = "of string";
result = lv + rval;
printf(result);
result = (lval + rv);
printf(result);
GCC 4.1.2で次のエラーが生成されます。
driver.cpp:25: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
String.h:22: note: candidate 1: String operator+(const String&, const char*)
String.h:24: note: candidate 2: String String::operator+(const String&)
これまでのところ良いですよね?悲しいことに、私の文字列(const char *str)コンストラクターは、暗黙のコンストラクターとして非常に便利であるため、明示的なキーワードを使用してこれを解決するだけで、異なる問題が発生します。
さらに... STD :: Stringはこれに頼る必要はありません。その理由はわかりません。たとえば、basic_string.hでは、次のように宣言されています。
template<typename _CharT, typename _Traits, typename _Alloc>
basic_string<_CharT, _Traits, _Alloc>
operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
const basic_string<_CharT, _Traits, _Alloc>& __rhs)
template<typename _CharT, typename _Traits, typename _Alloc>
basic_string<_CharT,_Traits,_Alloc>
operator+(const _CharT* __lhs,
const basic_string<_CharT,_Traits,_Alloc>& __rhs);
等々。 Basic_Stringコンストラクターは明示的であると宣言されていません。どうしてこれが私が得ているのと同じエラーを引き起こさないのではなく、どうやって同じ動作を達成できますか?
解決
あいまいさの理由は、ある候補関数が別の候補関数よりも優れている場合にのみ、 なし そのパラメーターのパラメーターは、他のパラメーターよりも悪い一致です。 2つの機能を検討してください。
friend String operator+(const String&, const char*); // (a)
String operator+(const String&); // (b)
あなたは呼んでいます operator+
とともに String
そしてa const char*
.
タイプの2番目の引数 const char*
, 、(a)(b)よりも明確に一致します。 (a)の正確な一致ですが、(b)にはユーザー定義の変換が必要です。
したがって、あいまいさがあるためには、最初の引数は(b)より良い(a)と一致する必要があります。
String
通話の左側 operator+
constではありません。したがって、それは(b)と一致します。これは、非コンストメンバー関数であり、(a)よりも優れています。 const String&
.
したがって、次のソリューションのいずれかが曖昧さを削除します。
- メンバーを変更します
operator+
constメンバー関数になる - 非会員を変更します
operator+
を取るString&
aの代わりにconst String&
- 電話
operator+
左側にconst文字列があります
明らかに、最初、 アンクルベンスによっても提案されています, 、行く最良の方法です。
他のヒント
この場合、で定義するだけで十分です operator+
:
String operator+(const String& lval, const String& rval);
あなたはaを取るコンストラクターを提供するからです char*
, 、a String
aから構築できます char*
通話中 operator+
. 。例えば:
String hello = "Hello, ";
const char* world = "world!";
String helloWorld = hello + world;
一時的な String
の内容で構築されます char*
world
(コンストラクターが明示的ではないため)、2つ String
オブジェクトは渡されます operator+
.
メンバーを宣言するとエラーが消えます + const 本来あるべきだ。
class String {
public:
String(const char*str);
friend String operator+ ( const String& lval, const char *rval );
friend String operator+ ( const char *lval, const String& rval );
String operator+ ( const String& rval ) const; //<-- here
};
しかし、理由がわからない。おそらく、可能であればconst参照よりも拘束力のある引数を好むので、最初の過負荷は左側の値に対してより良い一致であり、3番目の過負荷は右側の値に対してより良い一致を持っています。
より良い説明。 (問題を少し誤解している必要があります。)
printf(result);
あなたの文字列が暗黙の変換を持っていると私に言ってはいけません const char*
...それは悪です。
テンプレートとテンプレート以外の関数は、さまざまなルールに従います。テンプレート関数は、コンバージョンを適用することなく、実際のパラメータータイプで選択されます。テンプレート以外の場合(つまり、コード)、暗黙的な変換を適用できます。したがって、Basic_Stringのテンプレートされたものは曖昧ではありませんが、あなたのものです。
あなたはそれを示しました basic_string
の実装があります operator+
クラスの2番目と3番目のオペレーターに対応する String
. 。します basic_string
また、最初のオペレーターに対応するオペレーターも持っています[friend String operator+ ( const String& lval, const char *rval );
]?
このオペレーターを削除するとどうなりますか?