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

时间:2014-01-03 06:17:21

标签: c++ string templates operators temporary-objects

有谁知道为什么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到string的隐式转换在非临时对象(例如foo)上编译很好,
  • 以及转换为int(或long etc)时的临时对象
  • 通过方法
  • 转换为字符串时,它可以正常工作
  • 以及类型是const string&而不是字符串

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

如果删除模板定义和特化并简单地明确定义每个重载,则通过运算符隐式转换为字符串工作正常:

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

我不想使用此解决方法,因为它不太可维护。

有没有人知道另一种方法让main()的最后一行成功编译?我不认为Explicit conversion and templated conversion operator的接受答案在这里适用,因为无论是否涉及模板,都有可能进行多次转换(char *,alloc,string),而且对象是临时的这一事实似乎很重要。

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

1 个答案:

答案 0 :(得分:3)

不了解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进行编译。