tuple(const tuple<VValues...>& other) : m_head(other.head()), inherited(other.tail()) {}
static type get(tuple<Head, Values...>& t) { return t.head(); }
static const_type get(const tuple<Head, Values...>& t){ return t.head(); }
static type get(tuple<Head, Values...>& t) { return Next::get(t.tail()); }
static const_type get(const tuple<Head, Values...>& t) { return Next::get(t.tail()); }
inline ISAACAPI size_t numgt1(tuple const & tp) { return std::accumulate(tp.begin(), tp.end(), 0, [](size_t a, size_t b){ return a + (b>1); }); }
constexpr decltype(auto) get(tuple<T...> const& ts) { return *ts.unpack_into(get_impl<n>{}); }
inline ISAACAPI int_t min(tuple const & tp) { return std::accumulate(tp.begin(), tp.end(), std::numeric_limits<int_t>::max(), [](int_t a, int_t b){ return std::min(a, b); }); }
inline ISAACAPI int_t prod(tuple const & tp) { return std::accumulate(tp.begin(), tp.end(), 1, std::multiplies<int>()); }
bool operator==(const tuple<T, TTail...>& t, const tuple<U, UTail...>& u) { return t.head() == u.head() && t.tail() == u.tail(); }
bool operator<(const tuple<T, TTail...>& t, const tuple<U, UTail...>& u) { return (t.head() < u.head() || (!(t.head() < u.head()) && t.tail() < u.tail())); }
static PJ get(const tuple<Head, Values...>& t) { return t.head(); }
std::enable_if_t<!ndt::traits<tuple_element_t<I, tuple<T...>>>::is_same_layout, tuple_element_t<I, tuple<T...>>> get(const tuple<T...> &val) { return tuple_element_t<I, tuple<T...>>(val.metadata() + sizeof...(T) * sizeof(uintptr_t), val.data() + val.template offset<I>()); }
std::enable_if_t<ndt::traits<tuple_element_t<I, tuple<T...>>>::is_same_layout, tuple_element_t<I, tuple<T...>> &> get(const tuple<T...> &val) { return *reinterpret_cast<tuple_element_t<I, tuple<T...>> *>(val.data() + val.template offset<I>()); }
std::tuple<A,B...> to_std_tuple(){ return std::tuple_cat(std::make_tuple(a),rest.to_std_tuple()); }
bool operator()(const tuple<Alloc>& a) const { return a.match(m_pattern, m_binding); }