/ / Dlaczego stałe zmienne odwołanie nie może być powiązane z odwołaniem do wartości? - c ++, c ++ 11

Dlaczego niestabilna referencja nie może być powiązana z referencją rvalue? - c ++, c ++ 11

Chciałbym zrozumieć, dlaczego stałe zmienne odniesienie nie może być powiązane z odniesieniem wartości? Jaki jest racjonalny powód, aby zakazać takiej konwersji?

W poniższym kodzie komentuję wiersze, które się nie kompilują:

int main(){
int i=1;
//const volatile int& cvi2=std::move(i); -> ERROR: why?
const volatile int i2=0;
//const volatile int& cvi3=std::move(i2);// -> ERROR: why?
}

Oto bardziej realistyczny scenariusz, którego nie można skompilować z podobnego powodu:

#include<iostream>
template<class T> void g(const T& b){
//do usefull things
}
template<class T,class F> void f(T& a,F a_func){
//do usefull things with a
a_func(std::move(a));
}
int main(){
int i=0;
volatile int vi=1;
f(i,g<int>); //OK no error;
f(vi,g<volatile int>);//ERROR: can not convert volatile int to
//const volatile int &
}

W tym kodzie spodziewałbym się tego g<volatile int>(const volatile&) przyjąć dowolny argument.

Kolejna edycja, na bardziej konkretny przykład:

#include <vector>
using usefull_type=int;
void set_communication_channel_to(volatile usefull_type* g,size_t n);
int main(){
auto vect=
std::vector<volatile usefull_type>(10,usefull_type{42});//->ERROR no known conversion
// from int to const volatile int &
set_communication_channel_to(vect.data(),vect.size());
//...
//...
}

Musi istnieć dobry powód tego ograniczenia, nie?

Odpowiedzi:

7 dla odpowiedzi № 1

Prawidłowe pytanie powinno brzmieć „Dlaczego stałe zmienne odniesienie nie może być powiązane z wartością?? "

Poniższy kod również nie jest kompilowany, chociaż nie są bezpośrednio związane żadne odwołania do wartości:

const volatile int& cvr = 0;

Ta odpowiedź na powiązane pytanie przytacza odpowiednią sekcję normy:

Za [dcl.init.ref]/ 5, aby referencja była inicjowana przez powiązanie z wartością, referencja musi być a const nie-volatile odwołanie do wartości lub odwołanie do wartości:

- W przeciwnym razie odniesienie będzie odniesieniem wartościowym do trwałego typu stałego (tj. CV1 niech będzie const) lub odniesienie jest odniesieniem do wartości.

Domyślam się, że to ograniczenie ma charakter historycznywywodzi się ze standardu C ++ 98, gdzie wartości były ograniczone do tymczasowych, w pełni zarządzanych przez kompilator. Kompilator może umieścić wartość tymczasową pod dowolnym wybranym adresem lub rejestrem, a traktowanie go jako obiektu lotnego z możliwymi do zaobserwowania odczytami nie ma sensu. W nowym standardzie odwołanie do wartości można przekształcić w odwołanie do wartości za pomocą std::move(), jednak w rezultacie otrzymuje stare właściwości przyjęte dla wartości, tj. że ich dokładny adres pamięci jest nieznaczny, a zatem nie można mu przypisać atrybutu niestabilności.

Technicznie ograniczenie to nie jest bardzo ograniczające, ponieważ można skutecznie powiązać const volatile odniesienie do wartości poprzez dodatkowy poziom pośredni:

// This doesn"t compile
// const volatile int& cvr = 0;

// This does compile
const int& cr = 0;
const volatile int& cvr = cr;

4 dla odpowiedzi nr 2

Dosłowny powód jest taki, że [dcl.init.ref] zabrania takiej deklaracji:

Odwołanie do typu „cv1 T1” jest inicjalizowane przez wyrażenie typu „cv2 T2” w następujący sposób:
- Jeśli odwołanie jest odwołaniem do wartości i wyrażeniem inicjującym [...]
- W przeciwnym razie odniesienie powinno być odniesieniem wartości do trwałego typu stałego (tj. cv1 będzie const), lub referencja będzie referencją wartości.

Powód następnego poziomu to tylko zgadywanie (i problem z zadawaniem pytań): taka deklaracja nie ma sensu. Cel volatile jest wykonywanie wszystkich odczytów i zapisów możliwych do zaobserwowania zachowań. Jeśli inicjujesz odwołanie do const volatile tymczasowo, jesteś teraz właścicielem życia tego obiektu. Ale nie możesz do niego pisać. I nikt też nie może. Co więc robi volatile przenieść?