2017-09-08 53 views
16
#include <iostream> 

using namespace std; 

void func(int (&ref)[6]) { cout << "#1" << endl; } 
void func(int * &&ref) { cout << "#2" << endl; } 

int main() 
{ 
    int arr[6]; 
    func(arr); // g++(5.4): ambiguous, clang++(3.8): #2, vc++(19.11): #1 

    return 0; 
} 

Obie funkcje są dokładnie dopasowane. Poniżej znajduje się cytat z normą:Przeciążenie między wartością odniesienia lna a wartością rvalue

Standardowa sekwencja konwersja S1 jest lepsze niż sekwencja konwersja konwersja sekwencji standardowy S2 jeśli

...

S1 i S2 są powiązania referencyjne (8.5. 3) i nie odnosi się do niejawnego parametru obiektu niestatycznej funkcji składowej deklarowanej jako bez wartości odniesienia, a S1 wiąże odwołanie do wartości r do wartości , a S2 do wiązania wartości odniesienia o l. Wartości.

Czy to nie oznacza, że ​​drugi jest lepszy?

Aktualizacja:

There jest powiązany pytanie. Poniższy kod jest jego uproszczoną wersją.

#include <iostream> 

using namespace std; 

void func(int *&) { cout << "#1" << endl; } 
void func(int *&&) { cout << "#2" << endl; } 

int main() 
{ 
    int arr[6]; 
    func(arr); // g++(5.4) and clang++(3.8): #2, vc++(19.11): ambiguous 

    return 0; 
} 
+0

co masz na myśli mówiąc "lepiej"? – user463035818

+2

Fwiw, to [powiodło się z klangiem] (https://godbolt.org/g/gi1C9n) – WhozCraig

+0

To włącza, czy 'int (& ref) [6]' jest "odwołaniem do lwartości", jak podano w cytacie. Chociaż jest to odniesienie, można argumentować, że nie jest to odniesienie do lwartości. Jeśli tak, możesz przypisać 'ref', tzn.' Ref = '. Ale nie możesz. –

Odpowiedz

3

Myślę, że to zależy od tego, co oznacza konkretna fraza.

Oba konwersje są równoważne, ponieważ wyklucza lvalue transformations (w zasadzie, tablica skutecznie jest wskaźnikiem więc to się nie liczy jako konwersja), więc dostać się do następnego tiebreaker które wskazał w [over.ics.rank]:

S1 i S2 wiązania odniesienia i nie odnosi się do utajonego parametrów obiektu dla niestatycznych funkcji składowej deklarowanej bez rEF-kwalifikator i S1 wiąże odniesienia rValue do rvalue i S2 wiąże odniesienia lwartości

Czy ta sprawa ma zastosowanie? Mamy dwa wiązania referencyjne:

int arr[6]; 
int (&a)[6] = arr; // #1 
int *&& b = arr; // #2 

Tutaj, nr 1 wiąże referencję lwartości. # 2 wpada w numer [dcl.init.ref]:

W przeciwnym razie wyrażenie inicjalizacyjne jest niejawnie przekształcane na wartość typu "cv1 T1". Tymczasowa konwersja materializacji jest stosowana i odniesienie jest powiązane z wynikiem.

arr niejawnie przekształcić w prvalue typu int*, która jest następnie wiązana b.


Teraz pytanie brzmi - co oznacza ograniczenie w [over.ics.rank]? Może to oznaczać:

  • odniesienie rvalue, które jest ogólnie związane z wartością r. Jest to najwyraźniej interpretacja klang. Wartość odniesienia rvalue jest powiązana z wartością czasową zmaterializowaną na podstawie konwersji wartości arr.
  • w szczególności wyrażenie argumentu jest rwartością związaną z parametrem referencyjnym rvalue. Jest to interpretacja gcc na zasadzie zera, a ponieważ arr nie jest rwartością (jest to l-wartość), to rozstrzygnięcie jest pomijane i nie ma zastosowania żadne kolejne rozstrzygnięcia.

Jestem skłonny poprzeć wdrożenie GCC tutaj. W przeciwnym razie, jaki byłby sens zdania "wiąże wartość rwartości z wartością"? Odniesienia do wartości R nie mogą wiązać się z wartościami l. Jest zbędny. To powiedziawszy, jest też niezręcznie sformułowane w odniesieniu do tej interpretacji.

Jak to nazwieję, to błąd w słowie.

+0

Dla kompilatorów istnieją odpowiednie strony internetowe do dzielenia się frustracjami, jeśli coś nie działa zgodnie ze standardem ... Czy istnieje sposób na zgłoszenie raportu w przypadku standardowej wady? –

+1

@ W.F. Jest. https://isocpp.org/std/submit-issue – NathanOliver

+0

@NathanOliver thanks! –