Is there a better way to distinguish resizable containers than having allocator_type?

I have a template overload for operator>>()where I need to distinguish between the containers, which can be modified, for example vector, and containers that can not, for example array. Currently, I just use the tag allocator_type(see code below) - and it works fine - but wondered if there is a more explicit way to test this.

template <class T>
struct is_resizable {
    typedef uint8_t yes;
    typedef uint16_t no;

    template <class U>
    static yes test(class U::allocator_type *);

    template <class U>
    static no test(...);

    static const bool value = sizeof test<T>(0) == sizeof yes;
};

template <typename C>
typename boost::enable_if_c<
    boost::spirit::traits::is_container<C>::value && is_resizable<C>::value,
    istream &
>::type
operator>>(istream &ibs, C &c)
{
    c.resize(ibs.repeat() == 0 ? c.size() : ibs.repeat());
    for (typename C::iterator it = c.begin(); it != c.end(); ++it)
    {
        C::value_type v;
        ibs >> v;
        *it = v;
    }
    return ibs;
}

template <typename C>
typename boost::enable_if_c<
    boost::spirit::traits::is_container<C>::value && !is_resizable<C>::value,
    istream &
>::type
operator>>(istream &ibs, C &c)
{
    for (typename C::iterator it = c.begin(); it != c.end(); ++it)
        ibs >> *it;
    return ibs;
}
+4
source share
4 answers

Thanks to the help of @ Jarod42 on a separate issue, I have a solution that works with C ++ 98, C ++ 03 and C ++ 11; g ++ and VS2015. Also for the child task std::vector<bool>.

#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature)                \
    template <typename U>                                                    \
    class traitsName                                                         \
    {                                                                        \
    private:                                                                 \
        typedef boost::uint8_t yes; typedef boost::uint16_t no;              \
        template<typename T, T> struct helper;                               \
        template<typename T> static yes check(helper<signature, &funcName>*);\
        template<typename T> static no check(...);                           \
    public:                                                                  \
        static const bool value = sizeof check<U>(0) == sizeof(yes);         \
    }

DEFINE_HAS_SIGNATURE(has_resize_1, T::resize, void (T::*)(typename T::size_type));
DEFINE_HAS_SIGNATURE(has_resize_2, T::resize, void (T::*)(typename T::size_type, \
    typename T::value_type));

. , has_resize_1, has_resize_2 resize(). , ++ 11 resize() , ; ++ 11, : , . , VS2015, -, - . , .

, , has_resize<C>::value. , .

template <typename T>
typename boost::enable_if_c<
    !boost::spirit::traits::is_container<T>::value,
    xstream &>::type
    operator>>(xstream &ibs, T &b)
{
    return ibs;
}

template <typename C>
typename boost::enable_if_c<
    boost::spirit::traits::is_container<C>::value &&
    (has_resize_1<C>::value || has_resize_2<C>::value),
    xstream &
>::type
operator>>(xstream &ibs, C &c)
{
    typename C::value_type v;
    ibs >> v;
    return ibs;
}

template <typename C>
typename boost::enable_if_c<
    boost::spirit::traits::is_container<C>::value &&
    !(has_resize_1<C>::value || has_resize_2<C>::value),
    xstream &
>::type
operator>>(xstream &ibs, C &c)
{
    typename C::value_type v;
    ibs >> v;
    return ibs;
}
0

, resize -able, , resize(). ++ 03 :

template <typename T>
class has_resize
{
private:
    typedef char yes;
    struct no {
        char _[2];
    };

    template <typename U, U>
    class check
    { };

    template <typename C>
    static yes test(check<void (C::*)(size_t), &C::resize>*);

    template <typename C>
    static no test(...);

public:
    static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};
+4

. / (, boost::spirit::traits).

, . allocator_type, resize(...)

, ,

C::resize(size_t)

SFINAE

+1

++ :

template <typename T, typename = int>
struct resizable : std::false_type {};

template <typename T>
struct resizable <T, decltype((void) std::declval<T>().resize(1), 0)> : std::true_type {};

, - - resize, decltype :

decltype( (void) &T::resize, 0 )

, void , ( , )

+1
source

All Articles