暗黙的な変換:constリファレンスvs非コンストリファレンスvs非参照
-
11-10-2019 - |
質問
このコードを考慮してください、
struct A {};
struct B { B(const A&) {} };
void f(B)
{
cout << "f()"<<endl;
}
void g(A &a)
{
cout << "g()" <<endl;
f(a); //a is implicitly converted into B.
}
int main()
{
A a;
g(a);
}
これ 正常にコンパイルします, 、元気に動作します。しかし、私が変更した場合 f(B)
に f(B&)
, 、 それ コンパイルしません. 。私が書いたら f(const B&)
, 、それは再び 正常にコンパイルします, 、元気に動作します。なぜ理由と理論的根拠があるのですか?
概要:
void f(B); //okay
void f(B&); //error
void f(const B&); //okay
これらの各ケースについて、言語仕様からの理由、根拠、参照を聞きたいと思います。もちろん、関数署名自体は間違っていません。それよりも A
暗黙的に変換します B
と const B&
, 、しかし、ではありません B&
, 、それがコンパイルエラーを引き起こします。
解決
言語仕様から理由、根拠、参照を聞きたい
は C ++の設計と進化 十分な?
ただし、非控除の参照を非控除によって初期化することで、1つの深刻な間違いを犯しました[私によるコメント:その言葉遣いは不正確です!]。例えば:
void incr(int& rr) { ++rr; } void g() { double ss = 1; incr(ss); // note: double passed, int expected // (fixed: error in release 2.0) }
タイプの違いのため
int&
を参照することはできませんdouble
渡されたので、一時的に生成されて、保持しましたint
初期化ss
の価値。したがって、incr()
一時的なものを変更しました 結果は呼び出し関数に反映されていませんでした [私の強調].
考えてみてください:呼び出しの全体的な参照は、クライアントが関数によって変更されたものを渡し、関数が返された後、 クライアントは変更を観察できる必要があります.
他のヒント
問題は、AからA Bオブジェクトへの暗黙的な変換がRValueを生成することです。コンスト以外の参照は、LValuesにのみ結合できます。
Bにデフォルトのコンストラクターがあった場合、変更すると同じ動作が得られます f(a)
へ電話する f(B())
.
--
LITBは、LValueとは何かに対する素晴らしい答えを提供します。 スタックオーバーフロー - 頻繁に使用されるめったに定義されていない用語:lvalue
スタックオーバーフロー - コンスト以外の参照が一時的なオブジェクトにバインドできないのはなぜですか?
--
これらの関数呼び出しがどのように失敗または成功するかを標準に参照して説明することは、過度に長くなるでしょう。重要なことは方法です B& b = a;
whingが失敗します const B& b = a;
失敗しません。
(ドラフトN1905から)
タイプ「CV1 T1」への参照は、次のように「CV2 T2」タイプの式によって初期化されます。
- [はlvalueであり、参照互換性または暗黙的にコンバーチブルが参照互換型のlvalueに変換可能です...]
- それ以外の場合、参照は不揮発性の一型型(すなわち、CV1がconstでなければならない)への参照を行います。
これがそうです 何かが参照互換型のlvalueに変換可能な場合。