2013-03-13 5 views
11

Sto cercando di aggiornare un vecchio progetto che è stato creato con Visual Studio 2005 per utilizzare Visual Studio 2012 e I sto ottenendo un errore che non posso risolvere.Codice di operatore cast di tipo C++ che non verrà compilato in Visual Studio 2012, ma ha funzionato bene in Visual Studio 2005

Il codice che funziona bene sotto VS2005:

#include <iostream> 
#include <string> 
#include <sstream> 

using std::cout; 
using std::wcout; 
using std::endl; 
using std::wstring; 
using std::string; 


class Value 
{ 
public: 
    Value(const wstring& value) 
    { 
     v = value; 
    } 

    Value(Value& other) 
    { 
     this->v = other.v; 
    } 

    template<typename T> 
    operator T() const 
    { 
     T reply; 
     std::wistringstream is; 
     is.str(v); 
     is >> reply; 
     return reply; 
    } 

    operator wstring() const 
    { 
     return v; 
    } 


private: 
    wstring v; 
}; 


int main() 
{ 
    Value v(L"Hello World"); 

    wstring str = v; 
    wcout << str << endl; 

    Value int_val(L"1"); 
    int i = int_val; 

    cout << i + 1 << endl; 

    return 0; 
} 

Quando Sto compilando questo sotto VS2012 ottengo un errore sulla linea "wstring str = v;", l'errore è:

error C2440: 'initializing' : cannot convert from 'Value' to 'std::basic_string<_Elem,_Traits,_Alloc>' 
1>   with 
1>   [ 
1>    _Elem=wchar_t, 
1>    _Traits=std::char_traits<wchar_t>, 
1>    _Alloc=std::allocator<wchar_t> 
1>   ] 
1>   No constructor could take the source type, or constructor overload resolution was ambiguous 

Posso risolvere il problema cambiando la firma dell'operatore da 'operator wstring() const' a 'operator const wstring &() const'. Ma perché il codice originale non funziona, anche se funziona in VS2005.

Non ricevo un errore sulla riga "int i = int_val;".

Questo compila anche e gira bene con GCC (g ++) in cygwin (versione 4.5.3).

Aggiornamento Per simulare realmente il mio problema reale, alcune informazioni non erano disponibili nel codice di esempio riportato sopra. Tra la classe Value e l'uso ci sono poche altre classi. Uno che simile a questa:

class Config 
{ 
public: 
    virtual Value getValue(const string& key) const = 0; 

    Value operator()(const string& key) 
    { 
     return getValue(key); 
    } 
}; 

E l'utilizzo const wstring valore2 = config ("chiave");

Questo darà l'errore sopra durante la compilazione ma anche IntelliSense fornirà altri suggerimenti su cosa è sbagliato e dice: "Più di una conversione definita dall'utente da" Valore "a" const std: wstring "vale:" e punta sia al costruttore regolare che al costruttore di mosse di basic_string. Quindi sembra che abbia qualcosa a che fare con i rvalues ​​da fare e ho letto su questo e capisco le basi. Ma ci sono probabilmente molte cose che mi mancano.

trovo che posso risolvere questo problema modificando l'utilizzo di: const wstring & & value = config ("chiave");

Quindi sembra che il compilatore VS2012 capisca quale costruttore dovrebbe utilizzare.

Domande: * C'è un modo per non utilizzare & & in questo esempio? * Che cosa sta veramente succedendo qui?

ho messo il codice di esempio su GitHub: https://github.com/Discordia/ImplicitTypeConversion

+3

Compilano bene con Clang Trunk, quindi suppongo che sia un bug con la loro risoluzione di sovraccarico che non preleva il non-modello prima del modello (attraverso diversi possibili UCS). Si noti che esistono due costruttori validi: quello che prende 'wstring &&', e anche quello che prende' wchar_t const * '. Il primo invoca il comando di conversione 'wstring', mentre il secondo invoca il modello di conversione op. – Xeo

+0

@Xeo: o un errore comune in più compilatori. Su un rapido sguardo superficiale nello standard sembra * che VS potrebbe essere proprio qui. Non ho trovato alcuna regola che determini che la versione non-template abbia la precedenza su quella basata su modelli, e senza tale precedenza l'operatore di conversione è ambiguo quando converte in 'std :: wstring' e lo standard richiede che il codice fallisca. –

+0

@David: '§13.3.3/1:' "Date queste definizioni, una funzione valida' F1' è definita come una funzione migliore di un'altra funzione valida 'F2' se [...]' F1' è un la funzione non-template e 'F2' è una specializzazione del modello di funzione [...]" – Xeo

risposta

1

in termini semplici (si spera non semplificati), con C++ 11, si dovrà cominciare a pensare di riferimenti in termini di valore assegnabile e rvalue. Fondamentalmente, C++ 11 ti dà la possibilità di gestire le operazioni sui riferimenti in modo diverso a seconda che tu abbia a che fare con un oggetto "temporaneo". Questo ti dà la possibilità di fare cose come spostare dati interni al tuo oggetto piuttosto che copiarlo in diverse situazioni. Il lato negativo di questo è l'effetto che si sta vedendo, in cui il vecchio codice non è abbastanza specifico su cui si ha a che fare. C'è molto di più, non è qualcosa che può essere pienamente spiegato in una breve risposta SO, ma il precedente answers ha dato il via allo good places. Vorrei rielaborare il tuo codice per fornire sia operatori rvalue che lvalue (che sembra che tu sia già sulla buona strada per farlo).