Сделать авто стать ссылкой, если функция возвращает ссылку

Мне нужен следующий код для работы:

class Parent{
public:
     virtual void fun(){throw 0};

};

class Child:public Parent{
public:
     virtual void fun(){/*Success*/};

};
Parent& getChild(){
     return *(new Child());
}

void main(){
    auto child=getChild();
    child.fun();    
}

Но по какой-то причине auto создает Parent вместо Parent & который будет правильно использовать производный метод. Есть ли способ заставить auto создать ссылку вместо использования простого экземпляра?

1 ответ

Решение

Стандарт C++ объясняет, что auto вычитается из значения инициализатора:

Объявления [dcl.spec.auto]/1: auto а также decltype(auto) спецификаторы типа используются для обозначения типа заполнителя, который будет позже заменен вычитанием из инициализатора.

Инициализаторы [dcl.init]/1: Декларатор может указать начальное значение для идентифицируемого идентификатора.

Поэтому, когда вы пишете следующие объявления:

int t = f(10); 
auto x = y; 
auto child = getChild(); 

правая сторона оценивается как выражение, которое дает значение. И это значение используется для инициализации переменной, объявленной слева.

Значение не является ссылкой. Это не как указатели и адреса. При оценке выражения, когда используется ссылка, учитывается указанное значение. Вы можете увидеть это с помощью следующего простого фрагмента:

int x=15;
int&y = x; 
cout << x <<", " << y <<", " << &x<<endl;
cout << typeid(x).name() <<", " << typeid(y).name() <<", " << typeid(&x).name() <<endl; 

Следовательно, в вашем случае значение выражения Parent и не Parent &, Вот почему ваш auto будет выведено, чтобы иметь Parent тип.

Однако стандарт C++ не рассматривает все значения одинаково. В [basic.lval] это делает важное различие между различными типами значений, которые могут быть lvalues, xvalues и prvalues. В твоем случае getChild() оценивается как lvalue, то есть объект, на который вы ссылались, а не какая-то его временная копия.

Когда у вас есть такое lvalue, вы можете создать ссылку на него:

[dcl.ref]/ 2: ссылочный тип, который объявлен с использованием & называется ссылкой lvalue, (...)

Но вы должны сделать это явно, сказав, что ваш auto должен быть ссылкой:

auto &child = getChild();

Изменить: Больше информации о том, как работает авто: блог Херба Саттера GotW

Другие вопросы по тегам