换行模式std :: begin;返回开始(c);进入一个函数

时间:2017-12-30 00:19:47

标签: c++ c++11 c++14 c++17

有没有办法将模式包装成一般的模板函数?

template <typename C>
auto Begin(C&& c) -> ??? {
  using std::begin;
  return begin(std::forward<C>(c));
}

这里的问题是如何在这里写函数的返回类型?

我想要这个的原因是我想写一个模板变量

template <typename C>
constexpr bool IsBidirectionalContainer = 
  std::is_base_of<std::bidirectional_iterator_tag,
                  typename std::iterator_traits<
                      decltype(std::begin(std::declval<C>()))>::iterator_category>::value;

这里的问题是std::begin通过ADL找不到begin C的自定义重载。如果有人为此做了解决方法,也欢迎。

2 个答案:

答案 0 :(得分:9)

您需要将其包含在另一个名称空间中,即:

namespace details {
    using std::begin;

    template <typename C>
    auto Begin(C&& c) -> decltype(begin(std::forward<C>(c)))
    {
        return begin(std::forward<C>(c));
    }
}

然后:

template <typename C>
constexpr bool IsBidirectionalContainer = 
  std::is_base_of<std::bidirectional_iterator_tag,
                  typename std::iterator_traits<
                      decltype(details::Begin(std::declval<C>()))>::iterator_category>::value;

如果由于某种原因你拒绝在命名空间中定义Begin,你可以使用类型别名绕过它。

namespace details {
     using std::begin;

     template <typename C>
     using type = decltype(begin(std::forward<C>(c)));
}

template <typename C>
auto Begin(C&& c) -> details::type<C>
{
     return begin(std::forward<C>(c));
}

虽然这可能比必要的工作更多。前瞻声明可能就足够了。

答案 1 :(得分:1)

如果你要打包它,我想“为什么不使用最新的最佳创意?”具体来说,Eric Niebler makes an argument这些应该是函数调用对象,而不是函数!

这是我使用C ++ 17编译器的新版本

// ===================
// would be in a reusable header

namespace twostep {

    using std::begin;
    using std::end;

    inline auto Begin = [](auto&& r) -> decltype(begin(std::forward<decltype(r)>(r))) {
        return begin(std::forward<decltype(r)>(r));
    };

    inline auto End = [](auto&& r) -> decltype(end(std::forward<decltype(r)>(r))) {
        return end(std::forward<decltype(r)>(r));
    };

}

using twostep::Begin;
using twostep::End;

既然这并没有取代std::begin / end函数的实现,我没有得到Eric指出的所有好处。但是,除了作为一个包装器,为我做两步,作为一个正常的模板函数实现可以做,它本身免受ADL。

如果我提到具有资格的twostep::Begin,则没关系。但是,如果我将这些列入我自己的范围,因为此列表对全局范围有效,那么对Begin(r)的无限制调用肯定会看到此时我已看到的 one ,并且由于Begin中涉及的所有类型,因此在不同的命名空间中找不到名为r的函数。