Я пытаюсь обновить старый проект, который создавался с 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
Я могу это исправить, изменив сигнатуру оператора с ‘operator wstring () const’ на ‘operator const wstring&() const ‘. Но почему оригинальный код не работает, хотя он работает в VS2005.
Я не получаю сообщение об ошибке «int i = 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&& значение = config («ключ»);
Тогда кажется, что компилятор VS2012 понимает, какой конструктор он должен использовать.
Вопросы:
* Есть ли способ не использовать && в этом примере?
* Что на самом деле здесь происходит?
Я разместил пример кода на GitHub:
https://github.com/Discordia/ImplicitTypeConversion
Проще говоря (надеюсь, не упрощенно), в C ++ 11 вам придется начать думать о ссылках в терминах lvalue и rvalue. По сути, C ++ 11 дает вам возможность по-разному обрабатывать операции со ссылками в зависимости от того, имеете ли вы дело с «временным» объектом. Это дает вам возможность делать такие вещи, как перемещение данных внутри вашего объекта, а не копирование в различных ситуациях. Обратной стороной этого является эффект, который вы видите, когда старый код недостаточно конкретен, с которым вы имеете дело. Это нечто большее, это не совсем то, что может быть полностью объяснено в коротком ответе SO, но предыдущий ответы дал немного хорошие места начать. Я бы переработал ваш код, чтобы обеспечить как операторы rvalue, так и lvalue (похоже, вы уже на пути к этому).
Других решений пока нет …