template <typename T, typename = void>
struct is_iterable : std::false_type {};
// this gets used only when we can call std::begin() and std::end() on that type
template <typename T>
struct is_iterable<T, std::void_t<decltype(std::begin(std::declval<T&>())),
decltype(std::end(std::declval<T&>()))
>
> : std::true_type {};
// Here is a helper:
template <typename T>
constexpr bool is_iterable_v = is_iterable<T>::value;
6条答案
按热度按时间wxclj1h51#
你可以为此创造一个特性:
Live example.
qij5mzcb2#
cpprefence has an example answering your question。它使用的是SFINAE,下面是该示例的一个稍微修改的版本(以防该链接的内容随时间而更改):
这就是它的用途
输出:
话虽如此,它所检查的只是
begin() const
和end() const
的声明,因此相应地,甚至以下内容也被验证为可迭代对象:你可以看到这些片段在一起here
ekqde3dh3#
如果你在C++11或更高的保护伞下,当你必须专门化一个属性时,SFINAE检查的一个常用方法是如下:
诀窍如下:
false
。42
有int
类型,因此int
比unsigned
更匹配,得到true
。42
是因为它是所有问题的答案,灵感来自Eric Niebler的范围实现。在您的示例中,
C++11
具有可用于数组和容器的自由函数std::begin
和std::end
,因此必须工作的表达式为:如果你需要更多的通用性,表示某个东西是可迭代的方法还可以包括用户定义的类型,这些类型会为
begin
和end
带来自己的重载,所以你需要在这里应用一些adl
:您可以尝试使用此技术来获得更适合实际环境的解决方案。
eagi6jfj4#
解释
C::end()
存在,则check<C>(0)
调用check(int,const_iterator)
并返回const_iterator
兼容类型check<C>(0)
调用check(...)
(请参阅省略号转换)sizeof(check<C>(0))
取决于这些函数的返回类型value
设置为true
或false
参见coliru上的编译和测试运行
输出
另请参见jrok和Jarod42的类似回答。
此答案位于公共域中-CC0 1.0 Universal
jmp7cifd5#
这取决于你所指的“可迭代”。它在C中是一个松散的概念,因为你可以用很多不同的方式实现迭代器。
如果通过
foreach
您引用的是C11的基于范围的for循环,则该类型需要定义begin()
和end()
方法,并返回响应operator!=
,operator++
和operator*
的迭代器。如果您指的是Boost的BOOST_FOREACH辅助对象,请参见BOOST_FOREACH Extensibility。
如果在你的设计中你有一个所有可迭代容器都继承的公共接口,那么你可以使用C++11的std::is_base_of:
jljoyd4f6#
或者,如果(像我一样)你讨厌每一个SFINAE解决方案都是一大块伪结构体定义,其中包含
::type
和::value
的废话,那么下面是一个使用快速且(非常)肮脏的一行程序的示例:最后一个模板参数在一个步骤中执行多项操作:
1.检查该类型是否具有
begin()
成员函数或等效函数。1.检查
begin()
函数是否返回定义了operator*()
的内容(通常用于迭代器)。1.确定取消引用迭代器所产生的类型,并保存它,以防它在模板实现中有用。
限制:不仔细检查是否存在匹配的
end()
成员函数。如果您想要更健壮、更彻底、更可重用的解决方案,那么可以使用其他优秀的解决方案。