Roy*_*rau 25 c++ arrays iterable
有没有办法检查任意变量类型是否可迭代?
那么要检查它是否有索引元素,或者我可以实际循环它的孩子?(例如使用foreach?)
是否可以为此创建通用模板?
我在搜索时找到了其他编程语言的技巧.然而,仍然必须找到如何在C++中做到这一点.
Jar*_*d42 23
您可以为此创建一个特征:
namespace detail
{
    // To allow ADL with custom begin/end
    using std::begin;
    using std::end;
    template <typename T>
    auto is_iterable_impl(int)
    -> decltype (
        begin(std::declval<T&>()) != end(std::declval<T&>()), // begin/end and operator !=
        void(), // Handle evil operator ,
        ++std::declval<decltype(begin(std::declval<T&>()))&>(), // operator ++
        void(*begin(std::declval<T&>())), // operator*
        std::true_type{});
    template <typename T>
    std::false_type is_iterable_impl(...);
}
template <typename T>
using is_iterable = decltype(detail::is_iterable_impl<T>(0));
实例.
ani*_*b10 12
cpprefence 有一个例子来回答你的问题。它使用的是SFINAE,这是该示例的稍微修改版本(以防该链接的内容随着时间的推移而更改):
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;
现在,这就是它的使用方式
std::cout << std::boolalpha;
std::cout << is_iterable_v<std::vector<double>> << '\n';
std::cout << is_iterable_v<std::map<int, double>> << '\n';
std::cout << is_iterable_v<double> << '\n';
struct A;
std::cout << is_iterable_v<A> << '\n';
输出:
true
true
false
false
话虽如此,它检查的只是begin() constand的声明end() const,因此,即使以下内容也被验证为可迭代的:
struct Container
{
  void begin() const;
  void end() const;
};
std::cout << is_iterable_v<Container> << '\n'; // prints true
你可以在这里看到这些片段
这取决于你对"可迭代"的意思.它是C++中的一个松散概念,因为您可以通过许多不同的方式实现迭代器.
如果foreach您指的是C++ 11的基于范围的for循环,则需要定义类型需求begin()和end()方法,并返回响应的迭代器operator!=, 
 operator++和operator*.
如果你的意思是Boost的BOOST_FOREACH助手,那么请参阅BOOST_FOREACH可扩展性.
如果你的设计中有一个所有可迭代容器继承的公共接口,那么你可以使用C++ 11的std :: is_base_of:
struct A : IterableInterface {}
struct B {}
template <typename T>
constexpr bool is_iterable() {
    return std::is_base_of<IterableInterface, T>::value;
}
is_iterable<A>(); // true
is_iterable<B>(); // false
如果您在 C++11 及更高版本的保护伞下,当您只需要专门处理一个属性时,一种常用的 SFINAE 检查方法是以下一种:
template<class T, class = decltype(<expression that must compile>)>
inline constexpr bool expression_works(int) { return true; }
template<class>
inline constexpr bool expression_works(unsigned) { return false; }
template<class T, bool = expression_works<T>(42)>
class my_class;
template<class T>
struct my_class<T, true>
{ /* Implementation when true */ };
template<class T>
struct my_class<T, false>
{ /* Implementation when false */ };
诀窍如下:
false.42has type int,因此int比unsigned, getting更匹配true。42是因为它是一切的答案,灵感来自 Eric Niebler 的范围实现。在您的情况下,C++11具有自由函数std::begin并且std::end适用于数组和容器,因此必须工作的表达式是:
template<class T, class = decltype(std::begin(std::declval<T>()))
inline constexpr bool is_iterable(int) { return true; }
template<class>
inline constexpr bool is_iterable(unsigned) { return false; }
如果您需要更多的通用性,表达某事物可迭代的方法还可以包括用户定义的类型,这些类型为beginand带来自己的重载end,因此您需要在adl此处应用一些:
namespace _adl_begin {
    using std::begin;
    template<class T>
    inline auto check() -> decltype(begin(std::declval<T>())) {}
}
template<class T, class = decltype(_adl_begin::check<T>())>
inline constexpr bool is_iterable(int) { return true; }
template<class>
inline constexpr bool is_iterable(unsigned) { return false; }
您可以使用此技术来获得更适合您实际情况的解决方案。
template<typename C>
struct is_iterable
{
  typedef long false_type; 
  typedef char true_type; 
  template<class T> static false_type check(...); 
  template<class T> static true_type  check(int, 
                    typename T::const_iterator = C().end()); 
  enum { value = sizeof(check<C>(0)) == sizeof(true_type) }; 
};
check<C>(0)调用(check(int,const_iterator)如果C::end()存在)并返回const_iterator兼容类型check<C>(0)调用check(...)(请参阅省略号转换)sizeof(check<C>(0)) 取决于这些函数的返回类型value为true或false#include <iostream>
#include <set>
int main()
{
    std::cout <<"set="<< is_iterable< std::set<int> >::value <<'\n';
    std::cout <<"int="<< is_iterable< int           >::value <<'\n';
}
set=1
int=0
注意: C ++ 11(和C ++ 14)提供了许多特征类,但没有关于可迭代性的信息。
这个答案是在公共领域-CC0 1.0通用版
| 归档时间: | 
 | 
| 查看次数: | 6740 次 | 
| 最近记录: |