Сделать авто стать ссылкой, если функция возвращает ссылку - PullRequest
0 голосов
/ 24 ноября 2018

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

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 Ответ

0 голосов
/ 24 ноября 2018

Стандарт 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 &child = getChild();

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

...