is_container 和 add 的修改版

使用boost库对is_container的修改

利用现有boost库,对owensss实现的is_container等设施做一些更新,使代码更简洁

has_xxx.hpp

#ifdef TNAME
#include <type_traits>
#include <boost/preprocessor/cat.hpp>

template <class T>
struct BOOST_PP_CAT(has_, TNAME) {
    template <class>
    static constexpr bool test(...) {
        return false;
    }

    template <class U>
    static constexpr bool test(std::remove_reference_t<typename U::TNAME>*) {
        return true;
    }

    static constexpr bool value = test<T>(nullptr);
    using type = ::bool_<value>;
};

template <class T>
constexpr bool BOOST_PP_CAT(BOOST_PP_CAT(has_, TNAME), _v)
    = BOOST_PP_CAT(has_, TNAME)<T>::value;

#undef TNAME
#endif

has_mem.hpp

#ifdef TNAME
#include <boost/preprocessor/cat.hpp>
template <class T>
struct BOOST_PP_CAT(has_mem_, TNAME) {
    struct Fallback {int TNAME;};
    struct D : T, Fallback {};
    template <typename U, U> struct check;

    template <class>
    static constexpr bool test(...) {
        return true;
    }

    template <typename U>
    static constexpr
    bool test(check<int Fallback::*, &U::TNAME>*) {
        return false;
    }

    static constexpr bool value = test<D>(nullptr);
    using type = ::bool_<value>;
};

template <class T>
constexpr bool BOOST_PP_CAT(BOOST_PP_CAT(has_mem_, TNAME), _v) = BOOST_PP_CAT(has_mem_, TNAME)<T>::value;
#undef TNAME
#endif

添加 type 使满足mpl库的需求

and.hpp

#include <boost/mpl/and.hpp>

template <typename T, typename ...Args>
struct and_ : boost::mpl::and_<T, and_<Args...> >{};

template <typename T>
struct and_<T> : T {};

由于mpl::and_ 的参数个数有限,这里利用variadic template进行扩展

is_container.hpp

#include <boost/preprocessor/cat.hpp>
#include <type_traits>
#include <boost/mpl/bool.hpp>

template<bool T>
using bool_ = boost::mpl::bool_<T>;

namespace detail {
// a preprocess iteration will be better. I an not able to and not interested in making this done
#define TNAME value_type // value type
#include "has_xxx.hpp"
//...
#define TNAME empty // empty
#include "has_mem.hpp"
}
#include "and.hpp"

template <typename T>
struct is_container 
    : and_<
        std::is_class<T>,
        detail::has_value_type<T>,
        detail::has_reference<T>,
        detail::has_const_reference<T>,
        detail::has_const_iterator<T>,
        detail::has_difference_type<T>,
        detail::has_size_type<T>,
        detail::has_mem_begin<T>,
        detail::has_mem_cbegin<T>,
        detail::has_mem_end<T>,
        detail::has_mem_cend<T>,
        detail::has_mem_size<T>,
        detail::has_mem_max_size<T>,
        detail::has_mem_empty<T> >{};

template <class T>
constexpr bool is_container_v = is_container<T>::value;

使用 and_ 来连接需求,免去 impl class 的使用

add.hpp

#include "is_container.hpp"
#include <algorithm>
#include <boost/mpl/if.hpp>
#include <boost/mpl/or.hpp>

template <class T>
using rm_ref_t = std::remove_reference_t<T>;

#define is_both_container(C1_t, C2_t) 
        is_container<C1_t>::value 
        && (is_container<C2_t>::value || std::is_array<C2_t>::value) 
        && std::is_convertible< 
            typename boost::mpl::if_< 
                std::is_array<C2_t>, 
                std::remove_extent_t<C2_t>, 
                typename C2_t::value_type>::type, 
            typename C1_t::value_type>::value

template <class C1, class C2>
std::enable_if_t<is_both_container(rm_ref_t<C1>, rm_ref_t<C2>), rm_ref_t<C1>>
add(C1&& c1, const C2& c2) {
    auto res(std::forward<C1>(c1));
    std::copy(begin(c2), end(c2), back_inserter(res));
    return res;
}

template <class C, class ... Args>
        std::enable_if_t<
            and_<
                is_container<rm_ref_t<C>>,
                std::is_convertible<rm_ref_t<Args>, typename rm_ref_t<C>::value_type>...
            >::value, rm_ref_t<C>>
add(C&& c1, Args&& ... args) {
    using Container = rm_ref_t<C>;
    Container c2 = {static_cast<typename Container::value_type>(args)...};
    return add(std::forward<C>(c1), std::move(c2));
}

使用宏来减少代码,尽管尝试过使用中间类来封装调用,但因为不满足SFINAE 的条件,failed.

If a substitution results in an invalid type or expression, type deduction fails.
An invalid type or expression is one that would be ill-formed if written using the substituted arguments.
Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.

Leave a Reply

Your email address will not be published. Required fields are marked *