Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

templated conversion operator string() doesn't compile

The following compiles in VS 2005 but not in 2010 or 2012:

#include <string>

template <typename TT> TT getAs();
template <>            std::string getAs() { return "bye"; }
template <>            int getAs() { return 123; }

class Foo
{
public:
    template <typename TT>
        TT getAs() const { return ::getAs<TT>(); }

    template <typename TT>
        operator TT() const { return ::getAs<TT>(); }
};

Foo tempFoo() { return Foo(); }

int main()
{
    Foo foo;
    std::string testStringLocal = foo;                            // OK in 2010, FAIL in 2012
    int testIntTemp = tempFoo();                                  // OK
    std::string testStringTemp = tempFoo().getAs<std::string>();  // OK
    const std::string& testStringTemp2 = tempFoo();               // OK

    std::string testStringTemp3 = tempFoo();                    // FAIL!
}

Compiler complains on two lines of main() that conversion not possible. But if I replace the template definition of operator TT() by a set of equivalent overloads,

class Foo
{
public:
    template <typename TT>
        TT getAs() const { return ::getAs<TT>(); }

    operator std::string() const { return ::getAs<std::string>(); }
    operator int() const { return ::getAs<int>(); }
};

then everything builds fine. Note based on the main() lines that are marked OK that this problem is specific to template operator TT when string is template param AND (in 2010, but not in 2012) a temporary is involved.

Is this not valid code? Why is it valid in some cases?

like image 417
Oliver Avatar asked Jan 04 '14 07:01

Oliver


1 Answers

There seems to be an ambiguity between string's copy constructors.

Using this line solves the ambiguity:

std::string testStringLocal = (const std::string&)foo;

The same happens with operator=:

std::string testStringLocal;               // define empty string
testStringLocal = (const std::string&)foo; //OK
testStringLocal = foo;                     // Fail in all VS compilers (VS2010, 2012, 2013)

I don't know why std::string behaves differently than other classes, most likely the wealth of constructors and assignment operators.

When a compiler is given multiple options to perform a cast, and in this case a double cast (Foo -> string -> const string&) it will fail. It could also choose Foo -> int -> const string& or something of the sort.

like image 67
egur Avatar answered Oct 27 '22 12:10

egur