pan*_*nzi 4 c++ templates type-traits c++14
我编写了类似于类的特性,如果给定类型是"可迭代的",可以使用它来测试.这对于数组(for T[N],not for T[])以及具有a begin和end返回看起来像迭代器的方法的类都是如此.我想知道它是否可以比我更简洁/更简单地完成?
特别是impl命名空间中的东西看起来有点迂回/ hacky.这一切对我来说都有点难看.有关使用此示例并且可以使用g ++和clang ++编译的示例,请参阅:https://gist.github.com/panzi/869728c9879dcd4fffa8
template<typename T>
struct is_iterator {
private:
template<typename I> static constexpr auto test(void*)
-> decltype(
*std::declval<const I>(),
std::declval<const I>() == std::declval<const I>(),
std::declval<const I>() != std::declval<const I>(),
++ (*std::declval<I*>()),
(*std::declval<I*>()) ++,
std::true_type()) { return std::true_type(); }
template<typename I> static constexpr std::false_type test(...) { return std::false_type(); }
public:
static constexpr const bool value = std::is_same<decltype(test<T>(0)), std::true_type>::value;
};
namespace impl {
// implementation details
template<typename T>
struct has_iterable_methods {
private:
template<typename C> static constexpr auto test(void*)
-> decltype(
std::declval<C>().begin(),
std::declval<C>().end(),
std::true_type()) { return std::true_type(); }
template<typename C> static constexpr std::false_type test(...) { return std::false_type(); }
public:
static constexpr const bool value = std::is_same<decltype(test<T>(0)), std::true_type>::value;
};
template<typename T, bool HasIterableMethods>
struct returns_iterators : public std::false_type {};
template<typename T>
struct returns_iterators<T, true> {
typedef decltype(std::declval<T>().begin()) begin_type;
typedef decltype(std::declval<T>().end()) end_type;
static constexpr const bool value =
std::is_same<begin_type, end_type>::value &&
is_iterator<begin_type>::value;
};
}
template<typename T>
struct is_iterable : public std::integral_constant<
bool,
impl::returns_iterators<
typename std::remove_const<T>::type,
impl::has_iterable_methods<typename std::remove_const<T>::type>::value>::value> {};
template<typename T, std::size_t N>
struct is_iterable<T[N]> : public std::true_type {};
template<typename T>
struct is_iterable<T*> : public std::false_type {};
Run Code Online (Sandbox Code Playgroud)
首先,begin在std::begin可见的上下文中进行一些简单的参数依赖查找的样板:
#include <utility>
#include <iterator>
namespace adl_details {
using std::begin; using std::end;
template<class R>
decltype(begin(std::declval<R>())) adl_begin(R&&r){
return begin(std::forward<R>(r));
}
template<class R>
decltype(end(std::declval<R>())) adl_end(R&&r){
return end(std::forward<R>(r));
}
}
using adl_details::adl_begin;
using adl_details::adl_end;
Run Code Online (Sandbox Code Playgroud)
这需要合理地模拟基于范围的for(:)循环如何找到它们的开始/结束迭代器.通过这样打包,我们减少了下面的样板.
接下来,一些C++ 1y样式实用程序别名:
template<class>struct sink {using type=void;};
template<class X>using sink_t=typename sink<X>::type;
template<bool b, class T=void>using enable_if_t=typename std::enable_if<b,T>::type;
Run Code Online (Sandbox Code Playgroud)
sink_t采取任何类型,并抛弃它取代它void.
enable_if_t删除typename下面的烦人垃圾邮件.
在一个工业强度库中,我们将它放在details中,并且有一个1类型的参数版本可以发送给它.但我不在乎:
template<class I,class=void> struct is_iterator:std::false_type{};
template<> struct is_iterator<void*,void>:std::false_type{};
template<> struct is_iterator<void const*,void>:std::false_type{};
template<> struct is_iterator<void volatile*,void>:std::false_type{};
template<> struct is_iterator<void const volatile*,void>:std::false_type{};
template<class I>struct is_iterator<I,
sink_t< typename std::iterator_traits<I>::value_type >
>:std::true_type{};
Run Code Online (Sandbox Code Playgroud)
is_iterator不做重审核iterator_traits的I.但这已经足够了.
template<class R>
using begin_t=decltype(adl_begin(std::declval<R&>()));
template<class R>
using end_t=decltype(adl_end(std::declval<R&>()));
Run Code Online (Sandbox Code Playgroud)
这两种类型的别名使下面的东西不那么烦人.
再次,在工业强度库中,将2-arg-with- voidinto放入details:
template<class R,class=void> struct has_iterator:std::false_type{};
template<class R>
struct has_iterator<
R,
enable_if_t<
is_iterator<begin_t<R>>::value
&& is_iterator<end_t<R>>::value
// && std::is_same<begin_t<R>,end_t<R>>::value
>
>:std::true_type{};
Run Code Online (Sandbox Code Playgroud)
请注意enable_if_t上面注释掉的行.我把它留下来允许非对称迭代工作,其中end是一个具有不同operator==重载的类型.这正在考虑用于C++ 17:它允许在以null结尾的字符串上实现真正有效的算法(例如).
最后,最终输出:
template<class R>using iterator_t=enable_if_t<has_iterator<R>::type, begin_t<R>>;
Run Code Online (Sandbox Code Playgroud)
R如果它有一个迭代范围,则计算可迭代范围的迭代器.
有些情况下这不起作用,但它们是病态的.