11

我正在尝试更新一个使用 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;”行没有收到错误。

这也可以在 cygwin(版本 4.5.3)中使用 GCC(g++)编译和运行。

Update To really simulate my real problem there was some information left out in the sample code above. In between the Value class and the usage is a few other classes. One that look like this:

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

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

And the usage const wstring value2 = config("key");

That will give the error above when compiling but also IntelliSense will give other hints on whats wrong and it says: "More than one user-defined conversion from "Value" to "const std::wstring" applies:" and it points at both the regular constructor and the move constructor of basic_string. So it seem to have something to do with rvalues to do and I have been reading up on that, and understand the basics. But there is probably a lot I am missing.

I find that I can fix this problem by changing the usage to: const wstring&& value = config("key");

Then it seem like the VS2012 compiler understand which constructor it should use then.

Questions: * Are there a way to not use && in this example? * What is really happening here?

I put up the sample code on GitHub: https://github.com/Discordia/ImplicitTypeConversion

4

1 回答 1

1

In simple (hopefully not simplified) terms, with C++11, you'll have to start thinking of references in terms of lvalue and rvalue. Basically, C++11 gives you the ability to handle operations on references differently depending on whether or not you are dealing with a "temporary" object. This gives you ability to do things like move data internal to your object rather than copy in different situations. The down side to this is the effect you are seeing, where old code is not specific enough about which you are dealing with. There's more to it than that, it's not really something that can be fully explained in a short SO answer, but previous answers gave some good places to start. I would rework your code to provide both rvalue and lvalue operators (which it sounds like you're already on your way to doing).

于 2013-03-21T17:29:53.673 回答