有没有办法将模式包装成一般的模板函数?
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
的自定义重载。如果有人为此做了解决方法,也欢迎。
答案 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
的函数。