【问题标题】:ambiguous operator<< for templated overload模版重载的模棱两可的运算符<<
【发布时间】:2013-09-12 13:28:54
【问题描述】:

以下代码是我在 C++11 中第一次尝试漂亮地打印可迭代容器。它使用函数模板默认参数特性。

#include <ostream>
#include <string>
#include <utility>

template <typename T>
void print(std::ostream &o, T const &t) { o<< t; }

void print(std::ostream &o, std::string const &s){ o<< '"'<< s<< '"'; }

template <typename K, typename V>
void print(std::ostream &o, std::pair<K, V> const &p)
{
  o<< '{'; print(o, p.first);
  o<< ": "; print(o, p.second);
  o<< '}';
}

template <typename C, typename I= typename C::const_iterator>
std::ostream &operator<< (std::ostream &o, C const &c)
{
  o<< '[';
  if(c.empty()) return o<< ']';
  I b= c.begin(), e= c.end(); -- e;
  for(; b!= e; ++ b)
  {
    print(o, *b);
    o<< ", ";
  }
  print(o, *b);
  return o<< ']';
}

它适用于容器、容器容器等。除了一个例外:

std::cout<< std::string("wtf");

使用 g++4.7/8 编译会中断 ambiguous operator&lt;&lt;。

是否有任何修复此代码以避免歧义?

【问题讨论】:

  • 因为std::string 有一个const_iterator,所以你的operator&lt;&lt; 模板是匹配的。
  • @VaughnCato 是的,如果可能的话,我希望 std::basic_string 重载是首选。
  • 当C 是一个字符串时,您可以使用enable_if 来禁用您的重载。
  • OT,但您可以使用 auto b = c.begin() 而不是 I b

标签: templates c++11 operator-overloading pretty-print iterable


【解决方案1】:

您可以使用std::enable_if 来禁用字符串情况下的重载:

template <typename C, typename I= typename C::const_iterator>
typename std::enable_if<!std::is_same<C,std::string>::value,std::ostream>::type &
  operator<< (std::ostream &o, C const &c)
{
  o<< '[';
  if(c.empty()) return o<< ']';
  I b= c.begin(), e= c.end(); -- e;
  for(; b!= e; ++ b)
  {
    print(o, *b);
    o<< ", ";
  }
  print(o, *b);
  return o<< ']';
}

或者更笼统地说:

template <typename T>
struct is_string : std::false_type {};

template <typename Char,typename Allocator>
struct is_string<std::basic_string<Char,Allocator> > : std::true_type {};

template <typename C, typename I= typename C::const_iterator>
typename std::enable_if<!is_string<C>::value,std::ostream>::type &
  operator<< (std::ostream &o, C const &c)
{
  o<< '[';
  if(c.empty()) return o<< ']';
  I b= c.begin(), e= c.end(); -- e;
  for(; b!= e; ++ b)
  {
    print(o, *b);
    o<< ", ";
  }
  print(o, *b);
  return o<< ']';
}

【讨论】:

  • 好电话,我想在没有 enable_ifs(因此默认参数)的情况下这样做,但你还是给出了正确的答案。
猜你喜欢
  • 1970-01-01
  • 2010-12-10
  • 1970-01-01
  • 2013-11-18
  • 2014-09-26
  • 1970-01-01
  • 1970-01-01
  • 2019-09-12
相关资源
最近更新 更多