Код сценария типа С++, который не будет компилироваться в visual studio 2012, но отлично работал в visual studio 2005
Я пытаюсь обновить старый проект, созданный с помощью visual studio 2005, для использования visual studio 2012, и я получаю сообщение об ошибке, которое я не могу решить.
Код, который отлично работает в 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;
}
Когда я компилирую это под VS2012, я получаю сообщение об ошибке в строке "wstring str = v;", ошибка:
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
Я могу его исправить, изменив сигнатуру оператора от оператора wstring() const 'до' operator const wstring &() const '. Но почему исходный код не работает, хотя он работает в VS2005.
Я не получаю ошибку в строке "int я = int_val;".
Это также компилируется и работает отлично с GCC (g++) в cygwin (версия 4.5.3).
Обновление
Чтобы действительно смоделировать мою реальную проблему, в приведенном выше примере была некоторая информация. Между классом Value и использованием используется несколько других классов. Один из них выглядит следующим образом:
class Config
{
public:
virtual Value getValue(const string& key) const = 0;
Value operator()(const string& key)
{
return getValue(key);
}
};
И использование const wstring value2 = config ( "ключ" );
Это даст ошибку выше при компиляции, но также IntelliSense даст другие намеки на то, что не так, и говорит: "Применяется более одного пользовательского преобразования от" Value "до" const std:: wstring ":" и это указывает как на обычный конструктор, так и на конструктор перемещения basic_string. Похоже, что это имеет какое-то отношение к rvalues, и я читал об этом и понимаю основы. Но, вероятно, много чего мне не хватает.
Я нахожу, что могу исправить эту проблему, изменив использование: const wstring && value = config ( "ключ" );
Тогда похоже, что компилятор VS2012 понимает, какой конструктор он должен использовать тогда.
Вопросы:
* Есть ли способ не использовать && в этом примере?
* Что на самом деле происходит здесь?
Я приведу пример кода на GitHub:
https://github.com/Discordia/ImplicitTypeConversion
Ответы
Ответ 1
В простых (надеюсь, не упрощенных) условиях, с С++ 11, вам нужно будет начать думать о ссылках в терминах lvalue и rvalue. В основном, С++ 11 дает вам возможность обрабатывать операции над ссылками по-разному в зависимости от того, имеете ли вы дело с "временным" объектом. Это дает вам возможность делать такие вещи, как перенос данных внутри вашего объекта, а не копирование в разных ситуациях. Нижняя сторона этого - эффект, который вы видите, где старый код недостаточно специфичен, о котором вы имеете дело. Более того, это не совсем то, что можно полностью объяснить в коротком ответе SO, но предыдущие ответы дали несколько хорошие места. Я бы переработал ваш код, чтобы предоставить как rvalue, так и lvalue-операторы (что похоже на то, что вы уже на своем пути).