735 lines
20 KiB
C++
735 lines
20 KiB
C++
//-----------------------------------------
|
|
// Detail implementation of utils::variant
|
|
//-----------------------------------------
|
|
//
|
|
// Copyright kennytm (auraHT Ltd.) 2011.
|
|
|
|
// Boost Software License - Version 1.0 - August 17th, 2003
|
|
|
|
// Permission is hereby granted, free of charge, to any person or organization
|
|
// obtaining a copy of the software and accompanying documentation covered by
|
|
// this license (the "Software") to use, reproduce, display, distribute,
|
|
// execute, and transmit the Software, and to prepare derivative works of the
|
|
// Software, and to permit third-parties to whom the Software is furnished to
|
|
// do so, all subject to the following:
|
|
|
|
// The copyright notices in the Software and this entire statement, including
|
|
// the above license grant, this restriction and the following disclaimer,
|
|
// must be included in all copies of the Software, in whole or in part, and
|
|
// all derivative works of the Software, unless such copies or derivative
|
|
// works are solely in the form of machine-executable object code generated by
|
|
// a source language processor.
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
|
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
|
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
|
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
#ifndef VARIANT_IMPL_HPP_90M3SQU09PV
|
|
#define VARIANT_IMPL_HPP_90M3SQU09PV 1
|
|
|
|
#include <cassert>
|
|
#include <type_traits>
|
|
#include <climits>
|
|
#include "traits.hpp"
|
|
#if !defined(BOOST_NO_TYPEID)
|
|
#include <typeinfo>
|
|
#endif
|
|
|
|
namespace utils { namespace xx_impl {
|
|
|
|
//{{{ Utilities
|
|
|
|
static inline constexpr size_t max2(size_t a, size_t b) noexcept
|
|
{
|
|
return a > b ? a : b;
|
|
}
|
|
|
|
template <typename... F>
|
|
struct common_result_type
|
|
{
|
|
typedef typename std::common_type<typename function_traits<F>::result_type...>::type type;
|
|
};
|
|
|
|
//}}}
|
|
|
|
//{{{ Variadic unrestricted union (collapsed tuple)
|
|
|
|
template <typename...>
|
|
union union_impl;
|
|
|
|
template <typename T, typename... Rest>
|
|
union union_impl<T, Rest...>
|
|
{
|
|
T head;
|
|
union_impl<Rest...> rest;
|
|
|
|
typedef T First;
|
|
|
|
union_impl() noexcept {}
|
|
~union_impl() noexcept {}
|
|
};
|
|
|
|
template <typename T>
|
|
struct is_empty
|
|
{
|
|
enum {
|
|
value = std::is_same<
|
|
union_impl<>,
|
|
typename std::remove_cv<typename std::remove_reference<T>::type>::type
|
|
>::value
|
|
};
|
|
};
|
|
|
|
template <typename SV, typename T>
|
|
typename std::enable_if<!is_empty<T>::value, typename SV::result_type>::type
|
|
apply(T&& un, size_t index, SV& visitor)
|
|
{
|
|
if (index == 0)
|
|
return visitor(forward_like<T>(un.head));
|
|
else
|
|
return apply(forward_like<T>(un.rest), index-1, visitor);
|
|
}
|
|
|
|
template <typename SV, typename T>
|
|
typename std::enable_if<is_empty<T>::value, typename SV::result_type>::type
|
|
apply(T&&, size_t, SV&) { assert(false); }
|
|
|
|
template <typename SV, typename T1, typename T2>
|
|
typename std::enable_if<!is_empty<T1>::value && !is_empty<T2>::value,
|
|
typename SV::result_type>::type
|
|
apply2(T1&& un1, size_t index1, T2&& un2, size_t index2, SV& visitor)
|
|
{
|
|
if (index1 != 0)
|
|
return apply2(forward_like<T1>(un1.rest), index1-1, std::forward<T2>(un2), index2, visitor);
|
|
else if (index2 != 0)
|
|
return apply2(std::forward<T1>(un1), index1, forward_like<T2>(un2.rest), index2-1, visitor);
|
|
else
|
|
return visitor(forward_like<T1>(un1.head), forward_like<T2>(un2.head));
|
|
}
|
|
|
|
template <typename SV, typename T1, typename T2>
|
|
typename std::enable_if<is_empty<T1>::value || is_empty<T2>::value,
|
|
typename SV::result_type>::type
|
|
apply2(T1&&, size_t, T2&&, size_t, SV&) { assert(false); }
|
|
|
|
template <typename SV, typename T1, typename T2>
|
|
typename std::enable_if<!is_empty<T1>::value && !is_empty<T2>::value,
|
|
typename SV::result_type>::type
|
|
apply(T1&& un1, T2&& un2, size_t index, SV& visitor)
|
|
{
|
|
if (index == 0)
|
|
return visitor(forward_like<T1>(un1.head), forward_like<T2>(un2.head));
|
|
else
|
|
return apply(forward_like<T1>(un1.rest), forward_like<T2>(un2.rest), index-1, visitor);
|
|
}
|
|
|
|
template <typename SV, typename T1, typename T2>
|
|
typename std::enable_if<is_empty<T1>::value || is_empty<T2>::value,
|
|
typename SV::result_type>::type
|
|
apply(T1&&, T2&&, size_t, SV&) { assert(false); }
|
|
|
|
template <size_t index>
|
|
struct static_applier
|
|
{
|
|
template <typename V, typename union_type>
|
|
typename V::result_type operator()(union_type& un, V& visitor)
|
|
{
|
|
return static_applier<index-1>()(un.rest, visitor);
|
|
}
|
|
};
|
|
template <>
|
|
struct static_applier<0>
|
|
{
|
|
template <typename V, typename union_type>
|
|
typename V::result_type operator()(union_type& un, V& visitor)
|
|
{
|
|
return visitor(un.head);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
union union_impl<> {};
|
|
|
|
//}}}
|
|
|
|
//{{{ type_traits missing in std
|
|
|
|
template <typename T, typename U, typename = bool>
|
|
struct is_equatable
|
|
{
|
|
enum { value = false };
|
|
};
|
|
|
|
template <typename T, typename U>
|
|
struct is_equatable<T, U, decltype(std::declval<T>() == std::declval<U>())>
|
|
{
|
|
enum { value = true };
|
|
};
|
|
|
|
template <typename T, typename U, typename = bool>
|
|
struct is_less_than_comparable
|
|
{
|
|
enum { value = false };
|
|
};
|
|
|
|
template <typename T, typename U>
|
|
struct is_less_than_comparable<T, U, decltype(std::declval<T>() < std::declval<U>())>
|
|
{
|
|
enum { value = true };
|
|
};
|
|
|
|
template <typename T, typename U, typename = bool>
|
|
struct is_greater_than_comparable
|
|
{
|
|
enum { value = false };
|
|
};
|
|
|
|
template <typename T, typename U>
|
|
struct is_greater_than_comparable<T, U, decltype(std::declval<U>() < std::declval<T>())>
|
|
{
|
|
enum { value = true };
|
|
};
|
|
|
|
template <typename T, typename U, typename = bool>
|
|
struct is_assignable
|
|
{
|
|
enum { value = false };
|
|
};
|
|
|
|
template <typename T, typename U>
|
|
struct is_assignable<T, U, decltype(std::declval<T&>() = std::declval<U>(), true)>
|
|
{
|
|
enum { value = true };
|
|
};
|
|
|
|
template <typename T, typename U, typename = bool>
|
|
struct is_constructible
|
|
{
|
|
enum { value = std::is_constructible<T, U>::value };
|
|
};
|
|
|
|
template <typename T, typename U, typename = bool>
|
|
struct is_same
|
|
{
|
|
enum { value = std::is_same<T, U>::value };
|
|
};
|
|
|
|
template <typename To, typename From, typename = bool>
|
|
struct is_convertible
|
|
{
|
|
enum { value = std::is_convertible<From, To>::value };
|
|
};
|
|
|
|
template <typename T, typename U, typename = bool>
|
|
struct is_nothrow_assignable_helper
|
|
{
|
|
enum { value = false };
|
|
};
|
|
template <typename T, typename U>
|
|
struct is_nothrow_assignable_helper<T, U, typename std::enable_if<is_assignable<T, U>::value, bool>::type>
|
|
{
|
|
enum { value = noexcept(std::declval<T&>() = std::declval<U>()) };
|
|
};
|
|
|
|
template <typename T, typename U>
|
|
static constexpr bool is_nothrow_assignable() noexcept
|
|
{
|
|
return is_nothrow_assignable_helper<T, U>::value;
|
|
}
|
|
template <typename T>
|
|
static constexpr bool is_nothrow_move_constructible() noexcept
|
|
{
|
|
return std::is_nothrow_constructible<typename std::remove_reference<T>::type,
|
|
typename std::remove_reference<T>::type&&>::value;
|
|
}
|
|
|
|
template <typename T>
|
|
static constexpr bool is_nothrow_copy_constructible() noexcept
|
|
{
|
|
return std::is_nothrow_constructible<typename std::remove_reference<T>::type,
|
|
const T&>::value;
|
|
}
|
|
|
|
template <typename U>
|
|
static constexpr bool is_generic_nothrow_assignable() noexcept
|
|
{
|
|
return
|
|
(std::is_lvalue_reference<U>::value &&
|
|
xx_impl::is_nothrow_copy_constructible<U>()) ||
|
|
(std::is_rvalue_reference<U>::value &&
|
|
xx_impl::is_nothrow_move_constructible<U>());
|
|
}
|
|
|
|
//}}}
|
|
|
|
//{{{ Get index of type matching condition
|
|
|
|
static inline constexpr bool check_unambiguous(bool me_exact, bool else_exact, bool rest) noexcept
|
|
{
|
|
return me_exact && else_exact ? false : me_exact != else_exact ? true : rest;
|
|
}
|
|
|
|
template <typename T, typename U>
|
|
static inline constexpr bool is_same_upto_cv() noexcept
|
|
{
|
|
return std::is_same<typename std::remove_cv<
|
|
typename std::remove_reference<T
|
|
>::type>::type,
|
|
typename std::remove_cv<
|
|
typename std::remove_reference<U>::type
|
|
>::type>::value;
|
|
}
|
|
|
|
template <typename T, typename U>
|
|
static inline constexpr bool relaxed_same() noexcept
|
|
{
|
|
return (std::is_integral<T>::value && std::is_integral<U>::value)
|
|
|| (std::is_floating_point<T>::value && std::is_floating_point<U>::value);
|
|
}
|
|
|
|
template <typename, typename>
|
|
struct get_index_of_variant;
|
|
|
|
template <typename, template <typename, typename, typename=bool> class, typename...>
|
|
struct get_index;
|
|
|
|
// Given the type 'From', find the index of (T, Rest...) which are the same
|
|
// under the binary predicate 'Checker'.
|
|
template <typename From, template <typename, typename, typename=bool> class Checker, typename T, typename... Rest>
|
|
struct get_index<From, Checker, T, Rest...>
|
|
{
|
|
typedef get_index<From, Checker, Rest...> Tail;
|
|
|
|
static const bool is_exact_match = is_same_upto_cv<T, From>();
|
|
static const bool is_relaxed_match = relaxed_same<T, From>();
|
|
static const bool is_variant = is_variant<T>::value;
|
|
static const bool is_ud_match = Checker<T, From>::value;
|
|
static const bool is_strict_ud_match = is_ud_match && !is_variant;
|
|
|
|
typedef typename get_index_of_variant<From, T>::type variant_indices;
|
|
static const int var_quality = is_variant ? variant_indices::quality - 2 : 0;
|
|
|
|
// Match quality:
|
|
// exact > su > rel > strict_ud > ud
|
|
static const int local_quality_0 = is_exact_match ? INT_MAX
|
|
: is_relaxed_match ? INT_MAX-1
|
|
: is_strict_ud_match ? 2
|
|
: is_ud_match ? 1
|
|
: 0;
|
|
static const int local_quality = local_quality_0 < var_quality ? var_quality : local_quality_0;
|
|
static const bool is_match_here = local_quality > Tail::quality;
|
|
static const int quality = is_match_here ? local_quality : Tail::quality;
|
|
static const size_t index = is_match_here ? 0 : 1 + Tail::index;
|
|
static const bool ambiguous = local_quality == Tail::quality;
|
|
static const bool is_exact = quality == INT_MAX;
|
|
static const bool found = quality > 0;
|
|
|
|
/*
|
|
static void debug() noexcept
|
|
{
|
|
printf("%lu (%s vs %s) :: (lqual) %d (vqual) %d (tqual) %d (qual) %d (index) %lu (ambig) %d\n",
|
|
sizeof...(Rest)+1, typeid(From).name(), typeid(T).name(),
|
|
local_quality, var_quality, Tail::quality, quality, index, ambiguous);
|
|
|
|
if (is_variant)
|
|
{
|
|
printf("<< var <<\n");
|
|
variant_indices::debug();
|
|
printf(">> var >>\n");
|
|
}
|
|
|
|
Tail::debug();
|
|
}
|
|
*/
|
|
};
|
|
|
|
template <typename From, template <typename, typename, typename=bool> class Checker>
|
|
struct get_index<From, Checker>
|
|
{
|
|
static const int quality = 0;
|
|
static const size_t index = 0;
|
|
|
|
//static void debug() noexcept {}
|
|
};
|
|
|
|
template <typename From, typename>
|
|
struct get_index_of_variant
|
|
{
|
|
typedef get_index<From, is_same> type;
|
|
};
|
|
|
|
template <typename From, typename... T>
|
|
struct get_index_of_variant<From, variant<T...>>
|
|
{
|
|
typedef get_index<From, is_same, T...> type;
|
|
};
|
|
|
|
//}}}
|
|
|
|
//{{{ Visitors
|
|
|
|
template <typename T>
|
|
class getter_visitor : public static_visitor<T*>
|
|
{
|
|
public:
|
|
T* operator()(T& obj) const noexcept { return &obj; }
|
|
};
|
|
|
|
class destroy_visitor : public static_visitor<void>
|
|
{
|
|
public:
|
|
template <typename T>
|
|
void operator()(T& obj) const noexcept
|
|
{
|
|
obj.~T();
|
|
}
|
|
};
|
|
|
|
template <typename U>
|
|
class init_visitor_1 : public static_visitor<void>
|
|
{
|
|
public:
|
|
init_visitor_1(U&& field) noexcept : _field(std::forward<U>(field)) {}
|
|
|
|
template <typename T>
|
|
void operator()(T& obj) const noexcept(std::is_nothrow_constructible<T, U>::value)
|
|
{
|
|
new(&obj) T(std::forward<U>(_field));
|
|
}
|
|
|
|
private:
|
|
U&& _field;
|
|
};
|
|
|
|
class init_visitor_2 : public static_visitor<void>
|
|
{
|
|
public:
|
|
template <typename T, typename U>
|
|
void operator()(T& dest, U&& src) const noexcept(std::is_nothrow_constructible<T, U>::value)
|
|
{
|
|
new(&dest) T(std::forward<U>(src));
|
|
}
|
|
};
|
|
|
|
template <typename U>
|
|
class assign_visitor_1 : public static_visitor<void>
|
|
{
|
|
public:
|
|
assign_visitor_1(U&& field) : _field(std::forward<U>(field)) {}
|
|
|
|
template <typename T, typename = typename std::enable_if<is_assignable<T, U>::value>::type>
|
|
void operator()(T& obj) const noexcept(is_nothrow_assignable<T, U>())
|
|
{
|
|
obj = std::forward<U>(_field);
|
|
}
|
|
|
|
template <typename T, typename = typename std::enable_if<!is_assignable<T, U>::value>::type>
|
|
void operator()(T&&) const
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
private:
|
|
U&& _field;
|
|
};
|
|
|
|
template <typename V>
|
|
class assign_to_visitor : public static_visitor<void>
|
|
{
|
|
public:
|
|
assign_to_visitor(V& var) : _var(var) {}
|
|
|
|
template <typename T>
|
|
void operator()(T&& obj) const noexcept(is_nothrow_assignable<V, T>())
|
|
{
|
|
_var = std::forward<T>(obj);
|
|
}
|
|
|
|
private:
|
|
V& _var;
|
|
};
|
|
|
|
class is_nothrow_movable_checker : public static_visitor<bool>
|
|
{
|
|
public:
|
|
template <typename T>
|
|
bool operator()(const T&) const noexcept
|
|
{
|
|
return is_nothrow_move_constructible<T>();
|
|
}
|
|
};
|
|
|
|
class is_nothrow_copyable_checker : public static_visitor<bool>
|
|
{
|
|
public:
|
|
template <typename T>
|
|
bool operator()(const T&) const noexcept
|
|
{
|
|
return is_nothrow_copy_constructible<T>();
|
|
}
|
|
};
|
|
|
|
class is_nothrow_movable_checker_2 : public static_visitor<bool>
|
|
{
|
|
public:
|
|
template <typename T, typename U>
|
|
bool operator()(const T&, const U&) const noexcept
|
|
{
|
|
return std::is_nothrow_constructible<T, typename std::remove_reference<U>::type&&>::value;
|
|
}
|
|
};
|
|
|
|
class is_nothrow_copyable_checker_2 : public static_visitor<bool>
|
|
{
|
|
public:
|
|
template <typename T, typename U>
|
|
bool operator()(const T&, const U&) const noexcept
|
|
{
|
|
return std::is_nothrow_constructible<T, const U&>::value;
|
|
}
|
|
};
|
|
|
|
class assign_visitor_2 : public static_visitor<void>
|
|
{
|
|
public:
|
|
template <typename T, typename U, typename = typename std::enable_if<is_assignable<T, U>::value>::type>
|
|
void operator()(T& dest, U&& src) const noexcept(is_nothrow_assignable<T, U>())
|
|
{
|
|
dest = std::forward<U>(src);
|
|
}
|
|
|
|
template <typename T, typename U, typename = typename std::enable_if<!is_assignable<T, U>::value>::type>
|
|
void operator()(T&&, U&&) const
|
|
{
|
|
assert(false);
|
|
}
|
|
};
|
|
|
|
class swap_visitor_2 : public static_visitor<void>
|
|
{
|
|
public:
|
|
template <typename T, typename U>
|
|
void operator()(T& first, U& second) const
|
|
{
|
|
std::swap(first, second);
|
|
}
|
|
};
|
|
|
|
template <typename U>
|
|
class equals_visitor_1 : public static_visitor<bool>
|
|
{
|
|
public:
|
|
equals_visitor_1(const U& field) : _field(field) {}
|
|
|
|
template <typename T>
|
|
bool operator()(const T& other) const
|
|
{
|
|
return other == _field;
|
|
}
|
|
|
|
private:
|
|
const U& _field;
|
|
};
|
|
|
|
template <typename U>
|
|
class less_than_visitor_1 : public static_visitor<bool>
|
|
{
|
|
public:
|
|
less_than_visitor_1(const U& field) : _field(field) {}
|
|
|
|
template <typename T>
|
|
bool operator()(const T& other) const
|
|
{
|
|
return other < _field;
|
|
}
|
|
|
|
private:
|
|
const U& _field;
|
|
};
|
|
|
|
template <typename U>
|
|
class greater_than_visitor_1 : public static_visitor<bool>
|
|
{
|
|
public:
|
|
greater_than_visitor_1(const U& field) : _field(field) {}
|
|
|
|
template <typename T>
|
|
bool operator()(const T& other) const
|
|
{
|
|
return _field < other;
|
|
}
|
|
|
|
private:
|
|
const U& _field;
|
|
};
|
|
|
|
class equals_visitor_2 : public static_visitor<bool>
|
|
{
|
|
public:
|
|
template <typename T, typename U>
|
|
bool operator()(const T& first, const U& second) const
|
|
{
|
|
return first == second;
|
|
}
|
|
};
|
|
|
|
class less_than_visitor_2 : public static_visitor<bool>
|
|
{
|
|
public:
|
|
template <typename T, typename U>
|
|
bool operator()(const T& first, const U& second) const
|
|
{
|
|
return first < second;
|
|
}
|
|
};
|
|
|
|
class ostream_visitor : public static_visitor<std::ostream&>
|
|
{
|
|
public:
|
|
ostream_visitor(std::ostream& stream) : _stream(stream) {}
|
|
|
|
template <typename T>
|
|
std::ostream& operator()(const T& value)
|
|
{
|
|
return _stream << value;
|
|
}
|
|
|
|
private:
|
|
std::ostream& _stream;
|
|
};
|
|
|
|
class is_assignable_visitor : public static_visitor<bool>
|
|
{
|
|
public:
|
|
template <typename T, typename U>
|
|
bool operator()(const T&, const U&) const noexcept
|
|
{
|
|
return is_assignable<T, U>::value;
|
|
}
|
|
};
|
|
|
|
class is_same_visitor : public static_visitor<std::pair<bool, bool>>
|
|
{
|
|
public:
|
|
template <typename T, typename U>
|
|
std::pair<bool, bool> operator()(const T&, const U&) const noexcept
|
|
{
|
|
return std::make_pair(std::is_same<T, U>::value, is_assignable<T, U>::value);
|
|
}
|
|
};
|
|
|
|
template <typename... T>
|
|
class is_one_of_visitor : public static_visitor<bool>
|
|
{
|
|
public:
|
|
template <typename U>
|
|
bool operator()(const U&) const noexcept
|
|
{
|
|
return get_index<U, is_same, T...>::is_exact;
|
|
}
|
|
};
|
|
|
|
#ifndef BOOST_NO_TYPEID
|
|
class typeid_visitor : public static_visitor<const std::type_info&>
|
|
{
|
|
public:
|
|
template <typename U>
|
|
const std::type_info& operator()(const U& u) const noexcept
|
|
{
|
|
return typeid(u);
|
|
}
|
|
};
|
|
#endif
|
|
|
|
//}}}
|
|
|
|
template <typename SV>
|
|
class delayed_visitor
|
|
{
|
|
public:
|
|
explicit delayed_visitor(SV& visitor) : _visitor(visitor) {}
|
|
|
|
typedef typename SV::result_type result_type;
|
|
|
|
template <typename... T>
|
|
result_type operator()(T&&... val) const
|
|
{
|
|
return apply_visitor(_visitor, std::forward<T>(val)...);
|
|
}
|
|
|
|
private:
|
|
SV& _visitor;
|
|
};
|
|
|
|
//{{{ Functional-style apply
|
|
|
|
template <size_t index, typename T, typename... Rest>
|
|
struct apply_funcs_walker;
|
|
|
|
template <size_t index, typename T, typename Head, typename... Rest>
|
|
struct apply_funcs_walker<index, T, Head, Rest...>
|
|
{
|
|
auto operator()(T&& value, Head&& head_func, Rest&&... rest_funcs)
|
|
-> typename function_traits<apply_funcs_walker<index-1, T, Rest...>>::result_type
|
|
{
|
|
apply_funcs_walker<index-1, T, Rest...> functor;
|
|
return functor(std::forward<T>(value), std::forward<Rest>(rest_funcs)...);
|
|
}
|
|
};
|
|
|
|
template <typename T, typename Head, typename... Rest>
|
|
struct apply_funcs_walker<0, T, Head, Rest...>
|
|
{
|
|
auto operator()(T&& value, Head&& head_func, Rest&&...)
|
|
-> decltype(head_func(std::forward<T>(value)))
|
|
{
|
|
return head_func(std::forward<T>(value));
|
|
}
|
|
};
|
|
|
|
template <typename T, typename... F>
|
|
typename common_result_type<F...>::type
|
|
apply_funcs_check(T&& value, F&&... functions)
|
|
{
|
|
typedef get_index<T, is_convertible,
|
|
typename function_traits<F>::template arg<0>::type...> index_tmpl;
|
|
|
|
static_assert(index_tmpl::found, "Some variants are not handled.");
|
|
static_assert(!index_tmpl::ambiguous, "Applying variant to ambiguous list of functions.");
|
|
static constexpr size_t index_of_F = index_tmpl::index;
|
|
|
|
return apply_funcs_walker<index_of_F, T, F...>()(std::forward<T>(value), std::forward<F>(functions)...);
|
|
}
|
|
|
|
template <typename T, typename... F>
|
|
typename std::enable_if<!is_empty<T>::value, typename common_result_type<F...>::type>::type
|
|
apply_funcs_run(T&& un, size_t index, F&&... functions)
|
|
{
|
|
if (index != 0)
|
|
{
|
|
return apply_funcs_run(forward_like<T>(un.rest), index-1,
|
|
std::forward<F>(functions)...);
|
|
}
|
|
else
|
|
{
|
|
return apply_funcs_check(forward_like<T>(un.head),
|
|
std::forward<F>(functions)...);
|
|
}
|
|
}
|
|
|
|
template <typename T, typename... F>
|
|
typename std::enable_if<is_empty<T>::value, typename common_result_type<F...>::type>::type
|
|
apply_funcs_run(T&&, size_t, F&&...) { assert(false); }
|
|
|
|
|
|
|
|
//}}}
|
|
|
|
}}
|
|
|
|
#endif
|
|
|