【问题标题】:templated conversion operator string() doesn't compile模板化转换运算符 string() 无法编译
【发布时间】:2014-01-21 23:48:00
【问题描述】:

以下在 VS 2005 中编译,但在 2010 或 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!
}

编译器在main() 的两行中抱怨无法进行转换。但是如果我用一组等效的重载替换operator TT() 的模板定义,

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>(); }
};

然后一切正常。请注意,基于标记为 OK 的 main() 行,当字符串是模板参数并且(在 2010 年,但不是在 2012 年)涉及临时时,此问题特定于模板运算符 TT。

这不是有效的代码吗?为什么它在某些情况下有效?

【问题讨论】:

  • Compiles 关于 gcc 和 clang,以及 VS2013。
  • 你不需要定义 operator std::string 来编译它,你定义模板版本然后直接调用它:std::string testStringLocal = foo.operator std::string();
  • @praetorian 很高兴知道可能只是编译器错误
  • @emilcondrea 很有趣,但我绝不会要求我的用户使用这种晦涩难懂的语法。谈论破坏运算符重载的全部目的!
  • @Schollii 当然你不会,我只是指出编译器错误可能在哪里。

标签: c++ string templates operator-keyword


【解决方案1】:

字符串的复制构造函数之间似乎存在歧义。

使用这条线解决了歧义:

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

operator= 也是如此:

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

我不知道为什么std::string 的行为与其他类不同,很可能是大量的构造函数和赋值运算符。

当给编译器提供多个选项来执行强制转换时,在这种情况下,double cast (Foo -> string -> const string&amp;) 它将失败。它也可以选择Foo -> int -> const string&amp; 或类似的东西。

【讨论】:

  • 所以你不认为这是一个VC++编译器的bug?为了将foo 转换为const string &amp;,编译器必须首先使用operator string(),这与转换为string 必须使用的相同,因此它能够找到正确的字符串构造函数在一种情况下但不是在另一种情况下让我认为这是一个编译器错误。我已经为您的答案 +1,因为它是一种有用的解决方法,但它要求用户使用强制转换为 const ref,而很少有人会想到尝试。我必须证明 getAs&lt;TT&gt;() 可以用于任何 TT,而运算符 TT() 可以在某些情况下使用(待定)。
  • 可能是编译器错误,不知道。需要阅读规范才能完全给出答案。对我来说,这完全是理论上的。我永远不会写这样的代码,因为大多数开发团队的工程师经验很少,而且这种模板的使用有点过多(我的观点)。就个人而言,我想快速查看每个语句应该运行什么代码。
猜你喜欢
  • 2011-12-06
  • 2020-10-14
  • 1970-01-01
  • 1970-01-01
  • 2021-01-01
  • 2010-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多