【问题标题】:C++ ambigous overload for generic template ostream << operator通用模板 ostream << 运算符的 C++ 模棱两可的重载
【发布时间】:2015-05-29 13:54:17
【问题描述】:

这个问题在我之前的问题之后:Generic operator<< ostream C++ for stringifiable class 我想在其中实现一个通用的&lt;&lt;ostream 运算符,它适用于任何拥有to_str() 方法的类。

感谢answer,我已成功检查一个类是否实现了to_str() 方法并使用std::cout &lt;&lt; stringify(a)。但是,我很难编写模板 ostream&lt;&lt; 运算符以使 std::cout &lt;&lt; a 正常工作。

以下测试代码:

#include <iostream>
#include <sstream>
#include <string>

template<class ...> using void_t = void;

template<typename T, typename = void>
struct has_to_string
: std::false_type { };

template<typename T>
struct has_to_string<T, 
    void_t<decltype(std::declval<T>().to_str())>
    >
: std::true_type { };

template<typename T> std::enable_if_t<has_to_string<T>::value, std::string> 
stringify(T t) { 
    return t.to_str(); 
} 

template<typename T> std::enable_if_t<!has_to_string<T>::value, std::string> 
stringify(T t) { 
    return static_cast<std::ostringstream&>(std::ostringstream() << t).str(); 
} 

// The following does not work
/*
template<typename T> std::enable_if_t<has_to_string<T>::value, std::ostream&> 
operator<<(std::ostream& os, const T& t) {
    os << t.to_str();
    return os;
}

template<typename T> std::enable_if_t<!has_to_string<T>::value, std::ostream&> 
operator<<(std::ostream& os, const T& t) {
    os << t;
    return os;
}
*/

struct A {
    int a;
    std::string to_str() const { return std::to_string(a); }
};

struct B {
    std::string b;
    std::string to_str() const { return b; }
};

int main() {
    A a{3};
    B b{"hello"};
    std::cout << stringify(a) << stringify(b) << std::endl;    // This works but I don't want to use stringify
    // std::cout << a << b << std::endl;               // I want this but it does not work
}

给出与原始问题相同的错误。我做错了什么?

【问题讨论】:

  • 带有!has_to_string&lt;T&gt;::value 的版本会在os &lt;&lt; t 调用自身时产生无限递归。

标签: c++ templates c++11 ostream enable-if


【解决方案1】:

当类型为 std::string 时,您会收到一个 'operator 模糊重载错误,因为代码中的模板版本与 ostream 标头中提供的模板版本具有相同的优先级。

您可以通过更改测试程序来检查问题的根源:

int main() {
    std::cout << std::string("There is your problem") << std::endl;
}

你仍然会看到同样的错误。

为了解决这个问题,你可以添加一个显式的 operator

std::ostream& operator<<(std::ostream& os, const std::string& t) {
    using std::operator<<;
    os << t;
    return os;
}

【讨论】:

  • 哦,谢谢。确实有效......为什么现在类型 std::string 时会出现错误?如果可能的话,我们能不能写一个更简洁的代码而不是写3个overloaded operator&lt;&lt;
  • @coincoin 在我的回答中编辑以详细说明
  • @coincoin 我不知道任何技术可以避免编写另一个运算符
  • 谢谢。我开始相信这种对通用性的搜索在某种程度上是危险的,因为我改变了“标准”行为......
猜你喜欢
  • 2010-12-10
  • 2013-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多