Check if a variable type is iterable?

后端 未结 6 1024
失恋的感觉
失恋的感觉 2020-11-29 02:16

Is there any way to check if an arbitrary variable type is iterable?

So to check if it has indexed elements or I can actually loop over it\'s children? (Use foreach

6条回答
  •  广开言路
    2020-11-29 02:58

    If you are under the umbrella of C++11 and beyond, one usual way of SFINAE checking that works when you have to specialize for just one property, is the following one:

    template)>
    inline constexpr bool expression_works(int) { return true; }
    
    template
    inline constexpr bool expression_works(unsigned) { return false; }
    
    template(42)>
    class my_class;
    
    template
    struct my_class
    { /* Implementation when true */ };
    
    template
    struct my_class
    { /* Implementation when false */ };
    

    The trick is as follow:

    • When the expression doesn't work, only the second specialization will be instantiated, because the first will fail to compile and sfinae plays out. So you get false.
    • When the expression works, both overloads are candidate, so I have to force a better specialization. In this case, 42 has type int, and thus int is a better match than unsigned, getting true.
    • I take 42 because it's the answer to everything, inspired by Eric Niebler's range implementation.

    In your case, C++11 has the free functions std::begin and std::end that works for arrays and containers, so the expression that must work is:

    template()))
    inline constexpr bool is_iterable(int) { return true; }
    
    template
    inline constexpr bool is_iterable(unsigned) { return false; }
    

    If you need more generality, a way to express that something is iterable could also include user-defined types that brings their own overloads for begin and end, so you need to apply some adl here:

    namespace _adl_begin {
        using std::begin;
    
        template
        inline auto check() -> decltype(begin(std::declval())) {}
    }
    
    template())>
    inline constexpr bool is_iterable(int) { return true; }
    
    template
    inline constexpr bool is_iterable(unsigned) { return false; }
    

    You can play with this technique to achieve solutions that fits better your actual context.

提交回复
热议问题