2013-03-13 19 views
11

Próbuję zaktualizować stary projekt, który został zbudowany w studio graficznym 2005 do wykorzystania w studio wizualnym 2012, a ja Otrzymuję błąd, którego nie mogę rozwiązać.Kod operatora obslugi typu C++, który nie będzie kompilowany w Visual Studio 2012, ale działał dobrze w Visual Studio 2005

Kod, który działa dobrze pod 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; 
} 

Kiedy jestem kompilacji to pod VS2012 pojawia się błąd w wierszu "wstring str = v;", błąd jest:

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 

Mogę to naprawić, zmieniając sygnaturę operatora z "operator wstring() const" na "operator const wstring &() const". Ale dlaczego oryginalny kod nie działa, mimo że działa w VS2005.

Nie otrzymuję błędu na linii "int i = int_val;".

To również kompiluje i działa dobrze z GCC (g ++) w cygwin (wersja 4.5.3).

Aktualizacja Aby naprawdę zasymulować mój prawdziwy problem, niektóre informacje zostały pominięte w powyższym przykładowym kodzie. Pomiędzy klasą Value a użyciem jest kilka innych klas. Jeden, który wygląda tak:

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

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

A Wykorzystanie const wstring VALUE2 = config ("klucz");

To da błąd powyżej podczas kompilacji, ale również IntelliSense da inne wskazówki, co jest nie tak i mówi: "Zastosowanie ma więcej niż jedna konwersja zdefiniowana przez użytkownika z" Wartość "do" const std :: wstring ":" i wskazuje zarówno na zwykły konstruktor, jak i na konstruktor ruchu podstawowego. Wydaje się, że ma to coś wspólnego z rvalues ​​i czytałem o tym i rozumiem podstawy. Ale prawdopodobnie wiele brakuje mi.

uważam, że mogę rozwiązać ten problem poprzez zmianę wykorzystania do: const wstring & & value = config ("key");

Następnie wydaje się, że kompilator VS2012 rozumie, który konstruktor powinien wtedy użyć.

Pytania: * Czy istnieje sposób, aby nie używać w tym przykładzie & &? * Co tak naprawdę się dzieje?

kładę się przykładowy kod na GitHub: https://github.com/Discordia/ImplicitTypeConversion

+3

Kompiluje się dobrze z Clang Trunk, więc domyślam się, że jest to błąd z ich zbyt wysoką rozdzielczością, która nie wybiera szablonu przed szablonem (w różnych możliwych LUW). Zauważ, że istnieją dwa opłacalne konstruktory: jeden pobierający 'wstring &&', a także ten, który przyjmuje 'wchar_t const *'. Ten pierwszy wywołałby operację konwersji "wstring", podczas gdy druga wywoła szablon konwersji. – Xeo

+0

@Xeo: Lub typowy błąd w wielu kompilatorach. W szybkim pobieżnym wyglądzie w standardzie * wydaje się, że VS może być właśnie tutaj. Nie znalazłem żadnej reguły, która określałaby, że wersja bez szablonu ma pierwszeństwo przed szablonową, a bez tego pierwszeństwa operator konwersji jest niejednoznaczny podczas konwersji na 'std :: wstring', a standard wymaga, aby kod się nie powiódł. –

+0

@David: '§13.3.3/1:' "Biorąc pod uwagę te definicje, realna funkcja" F1 "jest zdefiniowana jako lepsza funkcja niż inna możliwa funkcja ' F2' jeśli [...] "F1" jest funkcja non-template i 'F2' to specjalizacja szablonów funkcji [...]" – Xeo

Odpowiedz

1

W prosty (oby nie uproszczone) warunki, z C++ 11, będziesz musiał zacząć myśleć o referencje w zakresie lwartości i rvalue. Zasadniczo, C++ 11 daje możliwość obsługi operacji na referencjach w różny sposób w zależności od tego, czy masz do czynienia z "tymczasowym" obiektem. Daje to możliwość przenoszenia danych wewnątrz obiektu, a nie kopiowania w różnych sytuacjach. Wadą tego jest efekt, w którym stary kod nie jest wystarczająco dokładny, z którym masz do czynienia. Jest w tym coś więcej, nie jest to naprawdę coś, co można w pełni wyjaśnić krótką odpowiedzią na WR, ale poprzednie answers dały początek pewnemu good places. Przerobiłbym twój kod, aby zapewnić zarówno rvalue, jak i lvalue operatorom (co brzmi, jakbyś już był na dobrej drodze).