views:

65

answers:

4

I'd really like to be able to assign a std::string object from a DecoratedString object that I'm writing.

class DecoratedString
{
private:
    std::string m_String;
public:
     DecoratedString(const std::string& initvalue)
     : m_String(initvalue)
     {
     }

     const std::string& ToString() const
     {
         return m_String;
     }

     const std::string& operator=(const DecoratedString& rhs)
     {
         return rhs.ToString();
     }

}

I've written a unit test to make sure this works:

void DecoratedStringTest::testAssignmentToString()
{
    std::string expected("test");
    DecoratedString sut(expected);
    std::string actual;
    actual = sut;

    CPPUNIT_ASSERT_EQUAL(actual, sut.ToString());
}

However, the compiler says error: no match for 'operator=' in 'actual = sut'. It then lists the overloaded operator= options from the standard library.

Why isn't the compiler finding the operator= I defined?

EDIT:

So I guess I need a conversion operator, not an assignment operator. Huge thanks to the people that saw what I was trying to do and explained what I should do instead.

+1  A: 

The compiler is complaining about this line:

actual = sut;

which should be:

actual = sut.ToString();

Alternatively you should provide a cast operator to implicitly convert a DecoratedString to a std::string:

class DecoratedString
{
    ...
    operator std::string() const
    {
        return ToString();
    }
};
jamesdlin
A cast operator? didn't know you could do that.
sheepsimulator
It's worth noting that since this answer uses an "operator std::string" and not a reference, this will create a copy of the return from ToString().
SoapBox
+1  A: 

You got it backwards. The operator= needs to be defined on the std::string to be able to accept your object, not the class you are assigning from, but since you are dealing with the standard library you can't do that.

An alternative would be a streaming operator (as a free function):

std::string& operator<<( std::string& out, const your_class& yc )
{
    out.assign( yc.to_string());
    return out;
}

your_class myobj;
std::string str;
str << myobj;

Or just define regular streaming for std::ostream and use std::stringstream.

Edit:

Yet another option, as others noted, is the type conversion operator:

your_class::operator const std::string() const;

Modern practice though tells us it's not the greatest idea (temporaries, extra copies, surprises).

Nikolai N Fetissov
+1  A: 

The operator = you have defined is for assigning decorated strings to other decorated strings and returning an std::string from that assignment.

What you want is a member "conversion operator" that automatically converts a decorated string to an std::string whenever required, like this:

operator std::string const &() const { return ToString(); }

That will also convert a decorated string automatically to a std::string const & whenever one is needed (i.e. when comparing to an std::string, or passing a DecoratedString to a function which takes a std::string const &).

SoapBox
+1  A: 

You're overloading the unary assignment operator that is intended for assigning a specific type to DecoratedString and is supposed to return a reference to DecoratedString so you can chain assignments. This operator is not designed to allow you to assign an object of DecoratedString to a different datatype, but rather so you can assign an object that isn't necessarily a DecoratedString to a DecoratedString. It also gives you a well-defined function to handle any sort of specific processing that an assignment of your class might required (deep copy, for example).

You either have to call your ToString() function or you'll have to create a conversion operator that can convert your DecoratedString into a std::string by implementing the following member function for DecoratedString:

operator std::string () const;

This might or might not be a good idea as this conversion operator will be used implicitly by the compiler and might lead to unexpected behaviour.

As an aside, another reason why your operator overload is not working is that you're trying to overload a function by its return value, which is a big no-no in C++.

Timo Geusch