Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Evaluation of type for auto in C++0X

Tags:

c++

c++11

I am playing around with the auto feature in the C++0X standard but I am confused how the decision of the type is made. Consider the following code.

struct Base
{
    virtual void f()
    {
        std::cout << "Base::f" << std::endl;
    }
};

struct Derived : public Base
{
    virtual void f()
    {
        std::cout << "Derived::f" << std::endl;
    }
};

int main()
{
    Base* dp = new Derived;
    auto b1 = *dp;
    auto& b2 = *dp;
    std::cout << typeid(b1).name() << std::endl;
    std::cout << typeid(b2).name() << std::endl;
}

It will print Base and Derived.
But why is the auto&evaluated to a ref to Derived and not to a ref to Base?
Even worse changing the code to this:

struct Base{};
struct Derived : public Base{};

int main()
{
    Base* dp = new Derived;
    auto b1 = *dp;
    auto& b2 = *dp;
    std::cout << typeid(b1).name() << std::endl;
    std::cout << typeid(b2).name() << std::endl;
}

returns Base for both types. So why is the type depended on the virtual functions? The compiler I am using is VS2010. Can anyone give me a hint where I can find the definition of this behavior in the standard?

like image 728
mkaes Avatar asked Jul 15 '11 12:07

mkaes


1 Answers

auto in both contexts is yielding Base, not derived. In the first case you are slicing the object (copy at the parent level) while in the second case, because it is a reference, you get a Base& to the actual Derived object. That means that all virtual function calls will be dispatched to the final overrider at the Derived level.

The typeid operator has different behavior for polymorphic types than for non-polymorphic ones. If applied to a reference to a polymorphic type it will perform a type check at runtime and yield the type of the actual object. If it is applied to an object or to a reference to a non-polymorphic type it will be resolved at compile time to the static type of the object or reference.

To verify what the auto is inferring, you can use a slightly different test:

void test( Base& ) { std::cout << "Base" << std::endl; }
void test( Derived& ) { std::cout << "Derived" << std::endl; }

Then call the function and see what type it is resolving to. I would expect the compiler to pick the first overload, as auto& a = *dp; should be equivalent to Base& a = *dp;

like image 167
David Rodríguez - dribeas Avatar answered Sep 28 '22 12:09

David Rodríguez - dribeas