2014-12-15 23 views
5

Przepraszam, jeśli tytuł pytania jest niedokładny - ale mam trudności ze zrozumieniem, co się tutaj dzieje.L-wartość zaniku do wartości z błędem automatycznym

Rozważmy następujące klasy:

struct foo { 
    foo(foo&); 
}; 

Poniższy ma żadnych błędów:

void func(foo& f) { 
    foo bar{f}; 
} 

Jednak kiedy używam Auto:

void func(foo& f) { 
    auto bar = foo{f}; 
} 

otrzymuję (GCC):

test.cpp: In function ‘void func(foo&)’: 
test.cpp:6:21: error: no matching function for call to ‘foo::foo(foo)’ 
test.cpp:6:21: note: candidate is: 
test.cpp:2:5: note: foo::foo(foo&) 
test.cpp:2:5: note: no known conversion for argument 1 from ‘foo’ to ‘foo&’ 

(szczęk)

test.cpp:6:10: error: no matching constructor for initialization of 'bar' 
    auto bar = foo{f}; 
     ^ ~~~~~~ 
test.cpp:2:5: note: candidate constructor not viable: expects an l-value for 1st argument 
    foo(foo&); 
    ^

Może ktoś proszę wyjaśnić dlaczego to błąd?

Dzięki!

Edycja: Działa, jeśli dodaję konstruktora kopii do foo. Miałem jednak wrażenie, że deklaracja zmiennej + jawne wywołanie konstruktora po prawej stronie składni "=" jest traktowane specjalnie i nie jest konstrukcją kopiującą, lecz bezpośrednią inicjalizacją.

Odpowiedz

8
auto bar = foo{f}; 

auto jest wyprowadzany jako foo. Następnie twoja definicja jest równoważna

foo bar = foo{f}; 

Próbujesz utworzyć obiekt typu foo, który jest kopią zainicjowany z prvalue foo{f}.

Problem polega na tym, że konstruktor kopiujący foo ma jako wartość nieokreśloną referencję lvalue, której nie można powiązać z wartością r. Ponadto konstruktor ruchu nie jest niejawnie zdefiniowany, ponieważ posiadasz deklarowany przez użytkownika konstruktor kopiowania. W związku z tym nie ma konstruktora, który może podjąć foo{f}, a kompilator wydaje komunikat o błędzie.

+0

Czy kompilator wyśle ​​wywołanie konstruktora kopiowania? Miałem wrażenie, że kompilator potraktuje to jako bezpośrednią inicjalizację. –

+0

Ahh pisanie na androidzie jest powolne i wydaje się, że nie ma sposobu, aby usunąć odpowiedź również –

+0

@RobertMason Kompilator może wywołać wywołanie konstruktora kopiowania, który nie ma skutków ubocznych, ale konstruktor kopii musi być nadal możliwy do wywołania. – Oktalist

3
auto bar = foo{f}; 

Jest to inicjowanie kopii, a poprzez swoją semantykę wymaga obecności konstruktora kopiowania. Jednak konstruktor kopiowania foo przyjmuje odwołanie niebędące const, a odwołanie niebędące const nie może być tymczasowe, czyli foo{f}.

Rozwiązaniem jest utworzenie konstruktora kopiowania, który pobiera odwołanie do const, jak zwykle robią to konstruktorzy kopii.