00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef __CHOICE_HH
00018 # define __CHOICE_HH
00019
00020 # include "../strategies.hh"
00021 # include <type_traits>
00022
00023 namespace aurelia {
00024
00028 template <typename T>
00029 T common_convertible(T, T);
00030
00031 template <typename T,
00032 typename U,
00033 typename =
00034 typename std::enable_if<std::is_convertible<U, T>::value>::type>
00035 T common_convertible(T, U);
00036
00037 template <typename T,
00038 typename U,
00039 typename =
00040 typename std::enable_if<std::is_convertible<T, U>::value>::type>
00041 U common_convertible(T, U);
00042
00043 template <typename Strat1, typename Strat2>
00044 struct choice_strategy;
00045
00049 template <typename Strat1, typename Strat2, typename T>
00050 struct strategy_model<choice_strategy<Strat1, Strat2>, T, false> {
00051 struct model {
00052 typedef typename strategy_model<Strat1, T>::model model1;
00053 typedef typename strategy_model<Strat2, T>::model model2;
00054
00055 typedef typename strategy_concept<model1>::check require1;
00056 typedef typename strategy_concept<model2>::check require2;
00057
00058 typedef choice_strategy<Strat1, Strat2> strat;
00059 typedef T input;
00060 typedef
00061 decltype(common_convertible(std::declval<typename model1::output>(),
00062 std::declval<typename model2::output>()))
00063 output;
00064 };
00065 };
00066
00069 template <typename Strat1, typename Strat2>
00070 struct choice_strategy {
00071 private:
00072 Strat1 s1;
00073 Strat2 s2;
00074 public:
00075 choice_strategy(const Strat1& s1, const Strat2& s2): s1(s1), s2(s2) {
00076 }
00077
00078 template <typename T>
00079 typename strategy_model<choice_strategy, T>::model::output
00080 operator()(const T& term) const {
00081 try {
00082 return s1(term);
00083 }
00084 catch (failure) {
00085 return s2(term);
00086 }
00087 }
00088 };
00089
00094 template <typename Strat1, typename Strat2>
00095 choice_strategy<Strat1, Strat2> operator+(const Strat1& s1, const Strat2& s2) {
00096 return choice_strategy<Strat1, Strat2>(s1, s2);
00097 }
00098 }
00099
00100 #endif