2014-06-30 18 views
11

Poniższe działa dobrze (jak można by oczekiwać):Szablon funkcji konwersji do const odniesień

struct X {}; 

struct A 
{ 
    operator X const&() 
    { 
    static const X value{}; 
    return value; 
    } 
}; 

int main() 
{ 
    A a; 
    X x = a; 
} 

Ale to nie jest tak oczywiste:

template<typename T> 
struct X {}; 

struct A 
{ 
    template<typename T> 
    operator X<T> const&() 
    { 
    static const X<T> value{}; 
    return value; 
    } 
}; 

int main() 
{ 
    A a; 
    X<int> x = a; 
} 

GCC 4.9 mówi error: conversion from ‘A’ to non-scalar type ‘X<int>’ requested natomiast Clang 3.4 ma żadnych problemów z tym. Jeśli usuniesz const lub & z funkcji konwersji lub jeśli napiszesz X<int> const &x = a, GCC również jest szczęśliwy.

W związku z tym GCC nie może znaleźć funkcji konwersji, jeśli typ docelowy to const & dla klasy szablonu, a użytkownik żąda konwersji na obiekt inny niż const & tej klasy. Czy to jest prawidłowe zachowanie? Próbowałem odczytać standard, ale zasady przeładowania są dla mnie dość mylące.

Odpowiedz

5

Tak, jest to błąd w gcc. To jest prawie dokładnie core DR976, jedyna różnica polega na tym, że w ich przykład typ docelowy jest typu non-klasa:

struct F { 
    template<class T> 
    operator const T&() { static T t; return t; } 
}; 

int main() { 
    F f; 
    int i = f; // ill-formed 
} 

Jako ze swoim przykładzie, dzyń akceptuje i gcc odrzuca ten przykład, niezależnie od standardowej wersji dialektu wybrany.

Zauważmy, że klauzula zmieniona że dr (14.8.2.3 [temp.deduct.conv]) nie dyskryminuje typów klasowych i non-klasy przeznaczenia, więc rozdzielczość że dr dotyczy kodu jednakowo.

Per zmienionym punkcie 14.8.2.3, kompilator powinien:

  • określić P, rodzaj powrotu szablonu funkcji konwersji, jak X<T> const & i A, żądany typ rezultacie, jak X<int>;
  • usuń odniesienie z P, podając X<T> const;
  • usuń kwalifikację cv z P, podając X<T>;
  • dedukuj T jako int.

Polecam złożenie zgłoszenia błędu na temat https://gcc.gnu.org/bugzilla/, odwołując się do DR.


Bo w Twoim przypadku jest to konwersja do typu klasy, istnieje obejście dostępny:

X<int> x1 = a;   // fails 
X<int> x2(a);   // OK 
X<int> x3 = X<int>(a); // also OK 

W bezpośrednim inicjalizacji konstruktorów typu docelowego są uważane (8.5p16); domyślny konstruktor kopiowania X<int> przyjmuje parametr typu X<int> const&, do którego, jak już widzieliśmy, gcc z przyjemnością konwertuje a.

+0

Dzięki waszemu wspaniałemu wyjaśnieniu i linkowi do raportu o usterce zgłosiłem zgłoszenie błędu: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61663 –

Powiązane problemy