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

Cha*_*ong 10 c++

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

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

这里的问题是,这将与现有的<<重载冲突.有没有办法在模板中指定C必须支持ranged-base for循环?

Dan*_*rey 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;
}
Run Code Online (Sandbox Code Playgroud)

实例

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


下面是一个更新的活生生的例子,其检测两个容器/支持类型begin(v)/ end(v)以及支持类型v.begin()/ v.end().


0x4*_*2D2 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;
}
Run Code Online (Sandbox Code Playgroud)