【发布时间】:2014-10-03 03:26:58
【问题描述】:
我编写了类型特征,例如可以用来测试给定类型是否“可迭代”的类。这适用于数组(对于T[N],不适用于T[])以及具有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 {};
【问题讨论】:
-
pretty printer 具有相似的类型特征。
-
++ (*std::declval<I*>())如果你想创建一个左值,为什么不直接++ std::declval<I&>()? -
begin(std::declval<T>())可能比std::declval<T>().begin()更好。 -
@Jarod42 在我看来,整个事情都可以通过 enable-ADL-technique
using std::begin; .. begin(std::declval<T&>())来简化。 -
这个问题属于 Stack Exchange 网络中的另一个站点:codereview.stackexchange.com
标签: c++ templates typetraits c++14