C++ type cast operator code that won't compile in visual studio 2012, but worked fine in visual studio 2005

StackOverflow https://stackoverflow.com/questions/15387109

Question

I'm trying to update a old project that has been building with visual studio 2005 to uses visual studio 2012, and I'm getting an error that I cant solve.

The code that works fine under 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;
}

When I'm compiling this under VS2012 I get an error on the line "wstring str = v;", the error is:

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

I can kinda fix it by changing the operator signature from 'operator wstring() const' to 'operator const wstring&() const'. But why does the original code not work, even though it works in VS2005.

I'm not getting an error on the line "int i = int_val;".

This also compiles and runs fine with GCC (g++) in cygwin (version 4.5.3).

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

Was it helpful?

Solution

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).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top