1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
|
//Utilitaire pour ajouter un type � la fin d'un tuple
template<class, class>
struct cat_type;
template<class T, class... Arg>
struct cat_type<std::tuple<Arg...>, T>
{
using type = std::tuple<Arg..., T>;
};
//Classe qui surcharge accept pour les types concret
template<class Abstract, class>
struct acceptable : Abstract
{
void accept(const typename Abstract::visitor_type& v)
{
v.visit(*this);
}
};
//Classe de base des visiteurs
//La visite se fait sur le type acceptable qui contient l'information sur le type r�el
template<class, class...>
struct visitor;
//R�cursion
template<class Abstract, class Concrete, class... Concrete_Tail>
struct visitor<Abstract, Concrete, Concrete_Tail...>
: visitor<Abstract, Concrete_Tail...>
{
using visitor<Abstract, Concrete_Tail...>::visit;
virtual void visit(acceptable<Abstract, Concrete>&) const = 0;
};
//Condition d'arr�t
template<class Abstract, class Concrete>
struct visitor<Abstract, Concrete>
{
visitor() = default;
visitor(const visitor&) = delete;
virtual ~visitor()
{
}
visitor& operator=(const visitor&) = delete;
virtual void visit(acceptable<Abstract, Concrete>&) const = 0;
};
//Utilitaire pour r�cup�rer le type accept� par la hi�rarchie depuis le visiteur
template<class, class>
struct accept_type;
template<
class Abstract, class... Concrete,
class T
>
struct accept_type<visitor<Abstract, Concrete...>, T>
{
using type = acceptable<Abstract, T>;
};
//Utilitaire pour r�cup�rer les types concrets de la hi�rarchie depuis le visiteur
template<class>
struct concrete_type;
template<class Abstract, class... Concrete>
struct concrete_type<visitor<Abstract, Concrete...>>
{
using type = std::tuple<Concrete...>;
};
//Classe de base qui ajoute accept � la classe de base de la hi�rarchie
template<class Abstract, class... Concrete>
struct accept_visitor
{
using visitor_type = visitor<Abstract, Concrete...>;
accept_visitor() = default;
accept_visitor(const accept_visitor&) = delete;
virtual ~accept_visitor()
{
}
accept_visitor& operator=(const accept_visitor&) = delete;
virtual void accept(const visitor_type&) = 0;
};
//Classe dispatcher : c'est un visiteur et un foncteur
//Condition d'arr�t sur les types de la hi�rarchie
template<
class To_Visit, class, bool,
class Visitor, class,
class Fun
>
struct dispatcher : Visitor
{
dispatcher(To_Visit& tv, const Fun& f)
: to_visit(tv), fun(f)
{
}
protected:
To_Visit& to_visit;
Fun fun;
};
//R�cursion sur les types de la hi�rarchie
template<
class To_Visit, class Visited,
class Visitor, class T, class... Concrete,
class Fun
>
struct dispatcher<
To_Visit, Visited, false,
Visitor, std::tuple<T, Concrete...>,
Fun
>
: dispatcher<
To_Visit, Visited, false,
Visitor, std::tuple<Concrete...>,
Fun
>
{
private:
using base = dispatcher<
To_Visit, Visited, false,
Visitor, std::tuple<Concrete...>,
Fun
>;
public:
using base::base;
//D�clenche la visite sur le bon param�tre
void operator()() const
{
std::get
<std::tuple_size<Visited>::value>
(base::to_visit)
.accept(*this);
}
using base::visit;
void visit(typename accept_type<Visitor, T>::type&) const
{
using new_visited = typename cat_type<Visited, T>::type;
//R�cursion sur les arguments d'appel
dispatcher<
To_Visit, new_visited,
std::tuple_size<To_Visit>::value == std::tuple_size<new_visited>::value,
Visitor, typename concrete_type<Visitor>::type,
Fun
>(base::to_visit, base::fun)();
}
};
//Condition d'arr�t sur les param�tre d'appel
template<
class To_Visit, class... Visited,
class Visitor, class Concrete,
class Fun
>
struct dispatcher<
To_Visit, std::tuple<Visited...>, true,
Visitor, Concrete,
Fun
>
{
dispatcher(To_Visit& tv, const Fun& f)
: to_visit(tv), fun(f)
{
}
//D�clenche l'appel avec les bon types
void operator()()
{
apply(std::make_index_sequence<sizeof...(Visited)>());
}
private:
template<std::size_t... I>
void apply(std::index_sequence<I...>)
{
fun(reinterpret_cast<Visited&>(std::get<I>(to_visit))...);
}
To_Visit& to_visit;
Fun fun;
};
//Classe de base pour les foncteurs � dispatcher
template<class Fun, class Abstract>
struct dispatchable
{
dispatchable() = default;
dispatchable(const dispatchable&) = default;
dispatchable& operator=(const dispatchable&) = default;
template<class... Arg>
void apply(Arg&&... arg)
{
using used_visitor = typename Abstract::visitor_type;
auto t = std::forward_as_tuple(std::forward<Arg>(arg)...);
dispatcher<
decltype(t), std::tuple<>, false,
used_visitor, typename concrete_type<used_visitor>::type,
Fun
>(t, static_cast<Fun&>(*this))();
}
protected:
~dispatchable()
{
}
}; |
Partager