Why is the Visual Studio compiler happy with
void fn(int *&i)
{
;
}
and
void fn(IUnknown *const &p)
{
;
}
but not
void fn(IUnkown *&p)
{
;
}
where calling it looks like
IDXGIFactory *df = nullptr;
// init df
fn(df);
compiler error is
3 IntelliSense: a reference of type "IUnknown *&" (not const-qualified) cannot be initialized with a value of type "IDXGIFactory *" c:\Users\Carl\Documents\Visual Studio 2013\Projects\Project1\Project5\main.cpp 29 10 Project5
The closest thing I've dug up with research is that the compiler will only do one type conversion at a time, but that can't be right because then the const & version should break from doing a type and const conversion; however it is the & version that actually won't compile.
A non-const lvalue reference (like
IUnknown*&
) can only bind to an lvalue; it cannot bind to an rvalue. A const-qualified lvalue reference (likeIUnknown* const&
) can bind to an rvalue.It's easier to consider a simpler case that does not involve pointers or function calls:
Here,
i
is an object of typeint
. Wheni
is used in an expression, it is an lvalue.In (1), we initialize the object
x
(of typedouble
) fromi
(of typeint
). The type does not match, but this is okay, because there is an implicit conversion fromint
todouble
. The "result" of this conversion is an rvalue expression(*) of typedouble
, which is used to initializex
.In (2), we initialize the const-qualified reference
y
(of typedouble const&
) fromi
. Again, the types do not match, so the implicit conversion is used to convert theint
todouble
. The "result" of this conversion is an rvalue. As noted at the beginning, a const-qualified reference can bind to an rvalue, soy
is bound to the "result" of the conversion.In (3), we attempt to initialize the non-const reference
z
(of typedouble&
) fromi
. The types do not match, so a conversion would be required. The conversion cannot be used here, because the "result" of the conversion is an rvalue, and as noted at the beginning, a non-const reference cannot bind to an rvalue.C++ has special rules to permit const lvalue references to bind to rvalue expressions. You can find out why from other questions here on StackOverflow, like "How come a non-const reference cannot bind to a temporary object?"
Your case is exactly the same as this one: the type of your argument (
IDXGIFactory*
) is not the same as the type of the parameter (IUnknown*
or a reference thereto), so an implicit conversion is required to convert the argument to the parameter type (in this case, it's a conversion from a pointer to a derived class to a pointer to a base class). The "result" of this conversion is an rvalue expression, however, so it cannot bind to the non-const referenceIUnknown*&
.(*)It's really a prvalue; I've used the C++98 expression taxonomy in this answer for simplicity. See this question for information about the C++11 value categories.