模板化运算符 string() 在临时对象时无法编译



有人知道main中最后一行编译失败的原因吗(注意,编译失败):

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!
}

正如我在对主线的评论中所指出的,

  • 从Foo到字符串的隐式转换在非临时对象(如Foo)上编译良好
  • 以及在转换为int(或long等)时对临时对象
  • 当通过方法转换为字符串时,它确实工作良好
  • 以及如果类型是const string&而不是字符串

在VS2010上尝试过此操作。请注意,上面的代码在2005年编译得很好,但我相信2010年是正确的。

如果我删除模板定义和专门化,并简单地显式定义每个重载,那么通过运算符隐式转换为字符串就可以了:

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

我宁愿不使用这种变通方法,因为它不太容易维护。

有人知道另一种方法可以成功编译main()的最后一行吗?我不认为显式转换和模板化转换运算符的公认答案适用于此,因为无论是否涉及模板,都可能有多个转换(char*、alloc、string),而且对象是临时对象这一事实似乎很重要。

编辑:这篇文章中的原始代码显示了一些类内模板专业化,这是从我的原始源代码中为SO创建一段独立代码的人工制品(我将一些命名空间级别的专业化移到了类中,VS2010没有抱怨)。问题是而不是专业化。我修改了发布的代码,使其更接近原始代码(正如我刚才所做的那样),不在类中使用专业化(当然问题仍然存在)。Derek的回答表明它可能是VS2010特有的。

不了解Visual C++2010(我认为是9.0版本),但您不能在类本身中专门化模板化的成员函数。根据我给这段代码的更现代的编译器发出的错误,它必须在命名空间范围内完成

所以,

#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!
}

使用Visual C++12.0和g++4.7.2进行精细编译。

最新更新