2014-06-30 20 views
11

I seguenti funziona bene (come ci si aspetterebbe):Template conversione a const riferimento

struct X {}; 

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

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

Ma non è così chiaro:

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 dice error: conversion from ‘A’ to non-scalar type ‘X<int>’ requested mentre clang 3.4 ha nessun problema con esso. Se si rimuove lo const o lo & dalla funzione di conversione o se si scrive X<int> const &x = a, GCC è anch'esso soddisfatto.

Quindi GCC non riesce a trovare la funzione di conversione solo se il tipo di destinazione è un const & in una classe modello e si richiede una conversione a un oggetto non const & di quella classe. È questo il comportamento corretto? Ho provato a leggere lo standard ma le regole di sovraccarico mi confondono molto.

risposta

5

Sì, questo è un bug in gcc. Questo è quasi esattamente core DR976, l'unica differenza è che nella loro esempio, il tipo di destinazione è di tipo non-classe:

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

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

Come con il tuo esempio, clang accetta e gcc rifiuta questo esempio, a prescindere dalla versione standard dialettale selezionato.

Nota che la clausola modificata da tale DR (14.8.2.3 [temp.deduct.conv]) non discrimina tra tipi di classe e di destinazione non di classe, quindi la risoluzione di quel DR si applica al codice altrettanto.

Per la clausola modificata 14.8.2.3, il compilatore dovrebbe:

  • determinare P, il tipo di ritorno della funzione di modello di conversione, come X<T> const &, e A, il tipo di risultato richiesto, come X<int>;
  • strisciare il riferimento da P, fornendo X<T> const;
  • strip la qualificazione cv da P, dando X<T>;
  • dedurre T come int.

Si consiglia di archiviare una segnalazione di bug su https://gcc.gnu.org/bugzilla/ facendo riferimento a tale DR.


Perché nel vostro caso si sta convertendo a un tipo di classe, c'è una soluzione disponibile:

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

In-inizializzazione diretta, costruttori del tipo di destinazione sono considerati (8.5p16); il costruttore di copie predefinito di X<int> utilizza un parametro di tipo X<int> const&, al quale, come abbiamo già visto, gcc è felice di convertire a.

+0

Grazie alla tua grande spiegazione e al link al rapporto sui difetti, ho presentato un bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61663 –

Problemi correlati