2011-08-31 6 views
16

ero Merily sperimentando con i nuovi tipi di ritorno finale, in cui mi ha colpito un problema con questo codice (semplificato)tipi restituiti trailing, decltype e const-ness

#include <list> 

class MyContainer{ 
    std::list<int> ints; 

    auto begin() -> decltype(ints.begin()) 
    { 
    return ints.begin(); 
    } 

    auto begin() const -> decltype(ints.begin()) 
    { 
    return ints.begin(); 
    } 
}; 

ignorano il fatto di come inutile questo codice è . La parte importante è l'errore del compilatore generato quando si usa GCC 4.6.1 (con -std=c++0x bandiera):

In member function 'std::list<int>::iterator MyContainer::begin() const': 
error: could not convert '((const MyContainer*)this)->MyContainer::ints.std::list<_Tp, _Alloc>::begin [with _Tp = int, _Alloc = std::allocator<int>, std::list<_Tp, _Alloc>::const_iterator = std::_List_const_iterator<int>]()' from 'std::list<int>::const_iterator {aka std::_List_const_iterator<int>}' to 'std::list<int>::iterator {aka std::_List_iterator<int>}' 

Nel caso in cui non sei di fan di errore che coinvolgono modelli, il racconto è che nel corpo del const versione MyContainer::begin, l'espressione ints.begin() restituisce un valore di tipo std::list<int>::const_iterator (poiché ints è const in tale contesto). Tuttavia, decltype(ints.begin()) produce il tipo std::list<int>::iterator, ad esempio decltypeignora il qualificatore const nel metodo begin quando si decide il tipo di espressione. Non sorprende che un conflitto di tipi sia il risultato.

Questo mi sembra un bug nel compilatore GCC. Avrebbe senso solo per decltype onorare il qualificatore const e produrre il tipo const_iterator. Qualcuno può confermare o negare (forse anche spiegare) questo? Forse sto trascurando qualcosa nella meccanica di decltype, ma questo sembra uno scenario piuttosto semplice.

Nota: per quanto posso dire, lo stesso comportamento vale non solo per std::list<int>, ma per qualsiasi tipo con funzioni membro sovraccarico su const -ness che restituiscono tipi incompatibili.

+2

Compila senza errori con l'istantanea recente di gcc 4.7.0. Fino ad allora, suppongo che tu sia bloccato con 'ints.cbegin()' – Cubbi

+0

Ovviamente, in un caso così banale questo non era un ostacolo serio, ma è importante che gcc lo faccia bene per tutti i casi non banali (I volevo anche assicurarmi che * I * abbia ragione - non desidero usare caratteristiche che non capisco). –

risposta

10

Si è corretto, questo è un bug. Secondo N3291, sezione 5.1.1, comma 3:

Se una dichiarazione dichiara una funzione membro o di un membro modello di funzione di una classe X, l'espressione si tratta di un prvalue di tipo “puntatore a cv-quali fi er-ss X "tra facoltativo cv-qualifer-seq e la fine della funzione-definizione, membro-dichiaratore o dichiaratore. Non deve comparire prima del cv-quali fi er-seq opzionale e non deve apparire all'interno della dichiarazione di una funzione membro statico (sebbene il suo tipo e la sua categoria di valore siano definiti all'interno di una funzione membro statico in quanto sono all'interno di una funzione membro non statico) . [Nota: questo è dovuto al fatto che la corrispondenza delle dichiarazioni non si verifica fino a quando non è noto il dichiaratore completo. -end note] A differenza dell'espressione dell'oggetto in altri contesti, * non è richiesto che sia di tipo completo per scopi di accesso ai membri della classe (5.2.5) al di fuori del corpo della funzione membro. [Nota: sono visibili solo i membri della classe dichiarati prima della dichiarazione. -end note]

Ma questo era un cambiamento recente tra l'ultima bozza di lavoro e N3291. Quindi GCC aveva ragione meno di 6 mesi fa; questo è il pericolo di scrivere codice su una specifica mobile.

+0

Questo è stato parte dei miei pensieri, come ho ricordato alcune discussioni sull'ultima bozza e l'uso di 'this' in un tipo di ritorno finale, ma non ero sicuro se nessuna delle proposte fosse effettivamente accettata. Grazie per la risposta ben referenziata. Per fortuna (secondo il commento di Cubby), GCC sembra essere in buona salute, dato che la versione 4.7 già affronta questo cambiamento. –