适用于所有类的漂亮打印,具有基于范围的for循环支持

时间:2013-10-26 16:09:02

标签: c++

我想通过重载<<来为所有具有ranged-base for for循环支持的类实现漂亮打印。 (错误的)代码是这样的。

template<class C> ostream& operator<<(ostream& out, const C& v) {
  for(auto x : v) out<<x<<' ';
  return out;
}

这里的问题是这会与现有的&lt;&lt;超载。有没有办法在模板中指定C必须支持ranged-base for loop?

3 个答案:

答案 0 :(得分:11)

由于基于范围的for循环要求begin(v)end(v)对ADL有效(并且std::是关联的命名空间),您可以使用:

namespace support_begin_end
{
    // we use a special namespace (above) to
    // contain the using directive for 'std':
    using namespace std;

    // the second parameter is only valid
    // when begin(C()) and end(C()) are valid
    template<typename C,
        typename=decltype(begin(std::declval<C>()),end(std::declval<C>()))
    >
    struct impl
    {
        using type = void; // only here impl
    };

    // explicitly disable conflicting types here
    template<>
    struct impl<std::string>;
}

// this uses the above to check for ::type,
// which only exists if begin/end are valid
// and there is no specialization to disable it
// (like in the std::string case)
template<class C,typename = typename supports_begin_end::impl<C>::type>
std::ostream& operator<<(std::ostream& out, const C& v) {
    for(auto x : v) out<<x<<' ';
    return out;
}

Live example

但是还有其他类型适合基于范围的循环。不知道你是否也需要检测它们。


这是一个更新的live example,可检测支持begin(v) / end(v)的容器/类型以及支持v.begin() / v.end()的类型。

答案 1 :(得分:6)

SFINAE:

template<class C>
auto operator<<(std::ostream& out, const C& v) -> decltype(v.begin(), v.end(), (out))
//                                          or -> decltype(std::begin(v), std::end(v), (out))
{
    for (auto x : v)
        out << x << ' ';
  return out;
}

答案 2 :(得分:4)

对所有答案的一般性评论:

使用

for (auto x : v)

将在打印之前复制集合中的所有元素,从而导致对复制构造函数和析构函数的大量调用。

你可能会更好
for (auto &x : v)

作为你的循环。