11

このコードを考えてみましょう。

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

これらのケースのそれぞれについて、言語仕様からの理由、理論的根拠、および参照を聞きたいと思います。もちろん、関数のシグネチャ自体は間違っていません。暗黙的にandにA変換されますが、 には変換されず、コンパイル エラーが発生します。Bconst B&B&

4

2 に答える 2

9

言語仕様から理由、理論的根拠、参考文献を聞きたい

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を保持するために一時が生成されました。したがって、一時的なものを変更しましたが、結果は呼び出し元の関数[強調鉱山]に反映されませんでした。intssincr()

考えてみてください。参照による呼び出しの全体的なポイントは、クライアントが関数によって変更されたものを渡すことであり、関数が戻った後、クライアントは変更を監視できる必要があります

于 2011-01-16T09:20:49.877 に答える
4

問題は、a から B オブジェクトへの暗黙的な変換によって右辺値が生成されることです。非 const 参照は左辺値にのみバインドできます。

B にデフォルトのコンストラクターがある場合、f(a)呼び出しを に変更すると、同じ動作が得られf(B())ます。

--

litb は、左辺値とは何かに対する優れた回答を提供します:スタック オーバーフロー - めったに定義されない用語をよく使用します: 左辺値

GotW #88: 「最も重要な定数」の候補</a>

スタック オーバーフロー - 非 const 参照が一時オブジェクトにバインドできないのはなぜですか?

--

これらの関数呼び出しがどのように失敗または成功するかを標準を参照して説明すると、非常に長くなります。大事なのはいかにB& b = a;失敗するか、失敗しconst B& b = a;ないかです。

(ドラフトn1905より)

型「 cv1 T1」への参照は、型「cv2 T2」の式によって次のように初期化
ます 。参照は、非揮発性の const 型に対するものでなければなりません (つまり、cv1 は const でなければなりません)。

これは、何かが参照互換型の左辺値に変換できる場合です。

于 2011-01-16T08:32:27.447 に答える