Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

templated operator string() won't compile when temp object

Does anyone know why the last line in main fails to compile (note it is compilation that fails):

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

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

Foo tempFoo() { return Foo(); }

int main()
{
    Foo foo;
    string testStringLocal = foo;       // OK
    int testIntTemp = tempFoo();        // OK
    string testStringTemp = tempFoo().getAs<string>();  // OK
    const string& testStringTemp2 = tempFoo();  // OK

    string testStringTemp3 = tempFoo(); //.getAs<string>();  // FAIL!
}

As I indicated by the comments for main's lines,

  • the implicit conversion from Foo to string compiles fine on a non-temp object (such as foo),
  • as well as on a temp object when converting to int (or long etc)
  • it does work fine when converting to string via a method
  • as well as if type is const string& instead of string

Tried this on VS2010. Note the above code compiles fine in 2005 but I believe 2010 is right.

Implicit conversion to string via operator works fine if I remove the template definition and specializations and simply define each overload explicitly:

class Foo
{
public:
    operator string() const { return ::getAs<string>(); }
    operator int()    const { return ::getAs<int>(); }
    ...
};

I'd prefer not to use this workaround as it is less maintainable.

Does anyone know of another way to have the last line of main() succesfully compile? I don't think the accepted answer to Explicit conversion and templated conversion operator applies here, because there are multiple conversions possible (char *, alloc, string) regardless of whether templates are involved, and the fact the object is a temporary seems to matter.

EDIT: Original code in this post showed some in-class template specialization, this was an artefact of creating a standalone piece of code for SO from my original source (I moved some namespace-level specializations into class and VS2010 did not complain). The issue is not specialization. I modified the posted code to be closer to original (as I just did), doesn't use in-class specialization (problem still there of course). Derek's answer indicates it might be specific to VS2010.

like image 854
Oliver Avatar asked Dec 07 '25 06:12

Oliver


1 Answers

Don't know about Visual C++ 2010 (version 9.0 I think), but you can't specialize a templated member function in the class itself. It must done at namespace scope, according to the errors emitted by more modern compilers I gave this code to.

So,

#include <string>
using namespace std;

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

template <>  inline Foo::operator string() const { return "hi"; }
template <>  inline Foo::operator int()    const { return 123; }
template <>  inline string Foo::getAs()  const { return "bye"; }

Foo tempFoo() { return Foo(); }

int main()
{
    Foo foo;
    string testStringLocal = foo;       // OK
    int testIntTemp = tempFoo();        // OK
    string testStringTemp = tempFoo().getAs<string>();  // OK

    string testStringTemp2 = tempFoo();  // OK!
}

Compiles fine with Visual C++ 12.0 and g++ 4.7.2.

like image 135
Cheers and hth. - Alf Avatar answered Dec 08 '25 19:12

Cheers and hth. - Alf



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!