C++ 递归AsString()以C++;

C++ 递归AsString()以C++;,c++,templates,C++,Templates,我正在尝试编写一个AsString()函数,根据我的喜好将STL容器转换为字符串。以下是我迄今为止提出的代码: template<class T> inline string AsString(const T& v); template<class First, class Second> inline string AsString(const pair<First, Second>& p); template<class Iter

我正在尝试编写一个AsString()函数,根据我的喜好将STL容器转换为字符串。以下是我迄今为止提出的代码:

template<class T>
inline string AsString(const T& v);

template<class First, class Second>
inline string AsString(const pair<First, Second>& p);

template<class Iter>
inline string PrintSequence(const char* delimiters, Iter begin, Iter end) {
  string result;
  result += delimiters[0];
  int size = 0;
  for (size = 0; begin != end; ++size, ++begin) {
    if (size > 0) {
      result += ", ";
    }
    result += AsString(*begin);
  }
  result += delimiters[1];
  result += StringPrintf("<%d>", size);
  return result;
}

#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \
template<class T1, class T2> \
inline string AsString(const Sequence<T1, T2>& seq) { \
  return PrintSequence("[]", seq.begin(), seq.end()); \
}

OUTPUT_TWO_ARG_CONTAINER(vector)
OUTPUT_TWO_ARG_CONTAINER(deque)
OUTPUT_TWO_ARG_CONTAINER(list)

template<class First, class Second>
inline string AsString(const pair<First, Second>& p) {
  return "(" + AsString(p.first) + ", " + AsString(p.second) + ")";
}

template<class T>
inline string AsString(const T& v) {
  ostringstream s;
  s << v;
  return s.str();
}

由于某种原因,编译器希望使用
运算符如果没有提供专门化,则重载了AsString。碰巧,您的后期重载并不比t const&version更受欢迎


相反,模板世界是美好的。。。对粗心的人来说是个真正的陷阱

一种专门化,是获取现有模板函数并指定其所有参数

template <typename T>
void foo(T const& t);

template <>
void foo<int>(int i); // this is a "complete" specialization

template <typename T, typename U>
void foo<std::pair<T,U>>(std::pair<T,U> const& pair);
  // this is a "partial" specialization
  // and by the way... it does NOT COMPILE

template <typename T, typename U>
void foo(std::pair<T,U> const& pair); // this is an overload
重载是将与另一个函数(无论是否为模板)相同的名称重新用于不同的参数集

template <typename T>
void foo(T const& t);

template <>
void foo<int>(int i); // this is a "complete" specialization

template <typename T, typename U>
void foo<std::pair<T,U>>(std::pair<T,U> const& pair);
  // this is a "partial" specialization
  // and by the way... it does NOT COMPILE

template <typename T, typename U>
void foo(std::pair<T,U> const& pair); // this is an overload
真正的问题是:
*begin
的类型是什么

嗯,
m
不合格:

  • Iter
    逻辑上是
    std::vector::迭代器
  • 因此,
    *begin
    的类型是
    std::vector&
因此,这两种过载可通过以下方式考虑:

  • (1) :
    T=std::vector
    ,需要转换为常量ref
  • (2) :
    T=int,U=std::allocator
    ,需要转换为const ref
应该选择第二个,因为据我所知,它更接近真实类型。我用VC++2010测试了它,结果它被选中了


你能不能也声明一个非常量限定的向量重载版本,看看它是否能满足你的编译器?(顺便说一句,我想知道它的名字。)

我不确定我是否明白答案。你看,当涉及到操作符重载时,我不想涉足名称空间解析业务,因为这会让我头晕目眩。不引入新名称空间就可以解决这个问题吗?另外,是否可以在不重载的情况下执行此操作
operator@LajosNagy:这是最简单的解决方案。如果你对这个答案有什么不理解的问题,我很乐意回答。好的,这是我不理解的。你说我没有专门化,而是重载了
AsString()
,这是什么意思。为什么
AsString()
可以在浅容器(如示例中)上工作,而不能在嵌套容器上工作?是什么让编译器为浅向量选择
AsString()
,而不是为嵌套向量的元素选择?@LajosNagy:我不知道代码中向量向量而不是整数向量的重载解析是如何失败的,但我知道您已经重载了AsString。首先,请记住,在当前C++中,不能部分地专门化函数。是的,我确实尝试了我的解决方案,效果很好:我的答案中包含了链接。您是否使用了
运算符进行了尝试或备注:我会将大小放在容器之前,而不是之后,这会使重新分析更容易。否则代码会很整洁(只需删除模板函数上的
内联
,这是不必要的)。这听起来是对的,这是OP使用的编译器中ADL中的一个bug。当然,我不太愿意提出编译器错误作为原因,但我知道2010年之前和其他编译器在这方面都有模板错误。@Fred:是的,除此之外,ADL模板和重载解析通常是脆弱的,考虑到涉及这方面的一系列规则,这并不让我感到惊讶。。。而右值引用和变量模板(argh)只会让情况变得更糟。我甚至不再相信自己能预测哪个函数会被选中:/gcc-4.4.3-glibc-2.11.1。顺便问一下,你认为申报单和它有什么关系吗?@Lajos:我不知道,正如我在之前的评论中所说的,我现在对标准中的所有规则都很模糊。以前很不容易,但现在很可怕:/
template <typename T>
void foo(T const& t);

template <>
void foo<int>(int i); // this is a "complete" specialization

template <typename T, typename U>
void foo<std::pair<T,U>>(std::pair<T,U> const& pair);
  // this is a "partial" specialization
  // and by the way... it does NOT COMPILE

template <typename T, typename U>
void foo(std::pair<T,U> const& pair); // this is an overload
template <typename T>
std::string AsString(const T& v); // (1)

template <typename T, typename Allocator>
std::string AsString(std::vector<T, Allocator> const& v); // (2)