Неявное преобразование: постоянная ссылка против неконстантной ссылки против неосновной - PullRequest
8 голосов
/ 16 января 2011

Рассмотрим этот код,

struct A {};
struct B {  B(const A&) {} };
void f(B)
{
    cout << "f()"<<endl;
}
void g(A &a)
{
    cout << "g()" <<endl;
    f(a); //a is implicitly converted into B.
}
int main()
{
    A a;
    g(a);
}

Этот прекрасно компилируется , работает нормально.Но если я изменю f(B) на f(B&), он не будет компилироваться .Если я напишу f(const B&), он снова скомпилируется нормально , работает нормально.Почему причина и обоснование?

Резюме:

void f(B);         //okay
void f(B&);        //error
void f(const B&);  //okay

Я хотел бы услышать причины, обоснование и ссылки из спецификации языка для каждого из этих случаев.Конечно, сигнатуры функций сами по себе не являются некорректными.Скорее A неявно преобразуется в B и const B&, но не в B&, что приводит к ошибке компиляции.

Ответы [ 2 ]

7 голосов
/ 16 января 2011

Я хотел бы услышать причины, обоснование и ссылку (я) из спецификации языка

Достаточно ли Дизайн и развитие C ++ достаточно?

Я допустил одну серьезную ошибку, позволив инициализировать неконстантную ссылку ненулевым значением [ мой комментарий: эта формулировка неточна! ]. Например:

void incr(int& rr) { ++rr; }

void g()
{
    double ss = 1;
    incr(ss);    // note: double passed, int expected
                 // (fixed: error in release 2.0)
}

Из-за разницы в типе int& не может ссылаться на переданный double, поэтому был создан временный объект для хранения int, инициализированного значением ss. Таким образом, incr() изменил временное значение, а результат не был отражен обратно в вызывающую функцию [ выделение шахты ].

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

4 голосов
/ 16 января 2011

Проблема в том, что неявное преобразование из объекта в объект B дает значение r. Неконстантные ссылки могут связываться только с lvalues.

Если бы B имел конструктор по умолчанию, вы бы получили то же поведение, если бы вы изменили вызов f(a) на f(B()).

-

litb дает отличный ответ на то, что является lvalue: Переполнение стека - часто используемые редко определяемые термины: lvalue

ПОЛУЧИЛСЯ № 88: Кандидат на «Самую важную константу»

Переполнение стека. Почему неконстантная ссылка не может привязаться к временному объекту?

-

Объяснять ссылками на стандарт, как эти вызовы функций терпят неудачу или преуспевают, было бы слишком долго. Важно то, как B& b = a; терпит неудачу, в то время как const B& b = a; не терпит неудачу.

(из черновика n1905)

Ссылка на тип «cv1 T1» инициализируется выражением типа «cv2 T2» следующим образом:
- [ является lvalue и может быть либо ссылочно-совместимым, либо неявно преобразованным в lvalue ссылочно-совместимого типа ... ]
- В противном случае ссылка должна быть на энергонезависимый константный тип (т. Е. Cv1 должен быть константным).

Вот случай, когда что-то может быть преобразовано в lvalue ссылочного совместимого типа.

...