Сделать авто стать ссылкой, если функция возвращает ссылку
Мне нужен следующий код для работы:
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