0

Visual Studio コンパイラが満足する理由

void fn(int *&i) 
{
    ;
}

void fn(IUnknown *const &p)
{
    ;
}

だがしかし

void fn(IUnkown *&p)
{
    ;
}

呼び出しがどのように見えるか

IDXGIFactory *df = nullptr;
// init df
fn(df);

コンパイラエラーは

3 IntelliSense: タイプ "IUnknown *&" (const 修飾されていない) の参照は、タイプ "IDXGIFactory *" の値で初期化できません c:\Users\Carl\Documents\Visual Studio 2013\Projects\Project1\Project5\main .cpp 29 10 Project5

私が研究で掘り下げた最も近いことは、コンパイラーが一度に 1 つの型変換しか実行しないということですが、それは正しくありません。なぜなら、const & version は型と const の変換を実行できなくなるからです。ただし、実際にコンパイルされないのは &バージョンです。

4

1 に答える 1

2

const でない左辺値参照 ( など) は、左辺値IUnknown*&にのみバインドできます。右辺値にバインドできません。const 修飾された左辺値参照 ( など)は、右辺値にバインドできます。IUnknown* const&

ポインターや関数呼び出しを含まない、より単純なケースを検討する方が簡単です。

int i = 0;

double        x = i; // (1) Well-formed
double const& y = i; // (2) Well-formed
double&       z = i; // (3) Ill-formed

ここでiは、タイプのオブジェクトですint。を式で使用するiと、左辺値になります。

(1)では、(型の) から(x型の)オブジェクトを初期化します。型が一致しませんが、 からへの暗黙的な変換があるため、これは問題ありません。この変換の「結果」は、初期化に使用されるtypeの右辺値(*)です。doubleiintintdoubledoublex

(2)では、 y(型のdouble const&) const 修飾された参照を から初期化しiます。ここでも型が一致しないため、暗黙的な変換を使用して を に変換intdoubleます。この変換の「結果」は右辺値です。冒頭で述べたように、 const 修飾された参照はrvalueにバインドできるためy、変換の「結果」にバインドされます。

(3)では、 からz(型のdouble&)非 const 参照を初期化しようとしますi。タイプが一致しないため、変換が必要になります。変換の「結果」はrvalueであり、冒頭で述べたように、非 const 参照はrvalueにバインドできないため、ここでは変換を使用できません。

C++ には、右辺値式にバインドする const 左辺値参照を許可する特別な規則があります。その理由は、 「非 const 参照が一時オブジェクトにバインドできないのはなぜですか?」など、StackOverflow に関する他の質問から確認できます。

あなたの場合はこれとまったく同じです: 引数の型 ( IDXGIFactory*) はパラメーターの型 (IUnknown*またはそれへの参照) と同じではないため、引数をパラメーターの型に変換するには暗黙的な変換が必要です (この場合、派生クラスのポインターから基底クラスへのポインターへの変換です)。ただし、この変換の「結果」は右辺値式であるため、非 const 参照にバインドできませんIUnknown*&


(*)それは本当に prvalue です。簡単にするために、この回答では C++98 式の分類法を使用しました。C++11 の値のカテゴリについては、この質問を参照してください。

于 2013-10-23T21:10:59.877 に答える