Created
August 15, 2010 14:51
-
-
Save sithhell/525569 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <boost/proto/proto.hpp> | |
#include <boost/fusion/include/pair.hpp> | |
#include <boost/fusion/include/as_map.hpp> | |
#include <boost/fusion/include/as_vector.hpp> | |
#include <boost/fusion/include/push_back.hpp> | |
using namespace std; | |
using namespace boost::proto; | |
struct param_domain; | |
//////////////////////////////////////////////////////////////////////////////// | |
// Parameters expression | |
//////////////////////////////////////////////////////////////////////////////// | |
template<typename Expr> | |
struct param_expr : extends<Expr, param_expr<Expr>, param_domain> | |
{ | |
typedef extends<Expr, param_expr<Expr>, param_domain> base_type; | |
explicit param_expr(Expr const &expr = Expr()) : base_type(expr) {} | |
BOOST_PROTO_EXTENDS_USING_ASSIGN(param_expr) | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// Add a parameters into the parameters map | |
//////////////////////////////////////////////////////////////////////////////// | |
struct _insert : boost::proto::callable | |
{ | |
template<class Sig> struct result; | |
template<class This, class Left, class Right, class State> | |
struct result<This(Left,Right,State)> | |
{ | |
typedef typename boost::remove_const<typename boost::remove_reference<Left>::type>::type left_type; | |
typedef typename boost::remove_const<typename boost::remove_reference<Right>::type>::type right_type; | |
typedef typename boost::remove_const<typename boost::remove_reference<State>::type>::type state_type; | |
typedef boost::fusion::pair<left_type, right_type> value_type; | |
typedef typename boost::fusion::result_of::push_back<state_type const, value_type>::type type; | |
}; | |
template<class Left, class Right, class State> | |
typename result<_insert(Left,Right,State)>::type | |
operator()(Left const& ,Right const& r,State& s) const | |
{ | |
return boost::fusion::push_back(s,boost::fusion::make_pair<Left>(r)); | |
} | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// Parameters Grammar | |
//////////////////////////////////////////////////////////////////////////////// | |
struct param_grammar | |
: or_< when< assign< _, _> | |
, _insert(_value(_left),_value(_right),_state) | |
> | |
, when< comma<param_grammar,param_grammar> | |
, param_grammar(_right, param_grammar(_left)) | |
> | |
> | |
{}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// Parameters domain: perform copy of the parameters value | |
//////////////////////////////////////////////////////////////////////////////// | |
struct param_domain : domain<generator<param_expr> > | |
{ | |
template <typename T> struct as_child : as_expr<T> {}; | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// Create a new parameters placeholder | |
//////////////////////////////////////////////////////////////////////////////// | |
#define BOOST_REGISTER_PARAMETERS(Name) \ | |
struct BOOST_PP_CAT(tag_,Name) {}; \ | |
param_expr<terminal<BOOST_PP_CAT(tag_,Name)>::type> const Name \ | |
/**/ | |
//////////////////////////////////////////////////////////////////////////////// | |
// Parameters pack | |
//////////////////////////////////////////////////////////////////////////////// | |
struct no_parameter_found {}; | |
template<class Map> struct parameters | |
{ | |
parameters( Map const& m ) : values(m) {} | |
template<class Sig> struct result; | |
template<class This, class Name> | |
struct result<This(param_expr<Name>)> | |
{ | |
typedef typename boost::fusion::result_of::has_key< | |
Map const | |
, typename boost::proto::result_of::value<Name>::type | |
>::type found; | |
typedef boost::fusion::result_of::at_key< | |
Map const | |
, typename boost::proto::result_of::value<Name>::type | |
> base; | |
typedef typename boost::mpl::eval_if<found, base, boost::mpl::identity<no_parameter_found> >::type type; | |
}; | |
template<class This, class Name, class Default> | |
struct result<This(param_expr<Name>,Default)> | |
{ | |
typedef typename boost::fusion::result_of::has_key< | |
Map const | |
, typename boost::proto::result_of::value<Name>::type | |
>::type found; | |
typedef boost::fusion::result_of::at_key< | |
Map const | |
, typename boost::proto::result_of::value<Name>::type | |
> base; | |
typedef typename boost::mpl::eval_if<found, base, boost::mpl::identity<Default> >::type type; | |
}; | |
template<class Name> | |
typename result<parameters(param_expr<Name>)>::type | |
operator()(param_expr<Name> const& p) const | |
{ | |
typedef typename boost::fusion | |
::result_of::has_key< Map const | |
, typename boost::proto | |
::result_of::value<Name>::type | |
>::type found; | |
return eval(p, found()); | |
//return boost::fusion::at_key<typename boost::proto::result_of::value<Name>::type>(values); | |
} | |
template<class Name, class Default> | |
typename result<parameters(param_expr<Name>,Default)>::type | |
operator()(param_expr<Name> const& p, Default const& v ) const | |
{ | |
typedef typename boost::fusion | |
::result_of::has_key< Map const | |
, typename boost::proto | |
::result_of::value<Name>::type | |
>::type found; | |
return eval(p,v, found()); | |
} | |
template<class Name, class Default> | |
typename result<parameters(param_expr<Name>,Default)>::type | |
eval(param_expr<Name> const&, Default const& , boost::mpl::true_ ) const | |
{ | |
return boost::fusion::at_key<typename boost::proto::result_of::value<Name>::type>(values); | |
} | |
template<class Name, class Default> | |
typename result<parameters(param_expr<Name>,Default)>::type | |
eval(param_expr<Name> const&, Default const& v, boost::mpl::false_ ) const | |
{ | |
return v; | |
} | |
template<class Name> | |
typename result<parameters(param_expr<Name>)>::type | |
eval(param_expr<Name> const&, boost::mpl::true_) const | |
{ | |
return boost::fusion::at_key<typename boost::proto::result_of::value<Name>::type>(values); | |
} | |
template<class Name> | |
typename result<parameters(param_expr<Name>)>::type | |
eval(param_expr<Name> const&, boost::mpl::false_) const | |
{ | |
BOOST_MPL_ASSERT_MSG(false, PARAMETER_NOT_FOUND, (Name)); | |
return no_parameter_found(); | |
} | |
Map values; | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// Option binder class | |
//////////////////////////////////////////////////////////////////////////////// | |
struct option_binder | |
{ | |
template<class X> struct result | |
{ | |
typedef typename boost::result_of < param_grammar ( param_expr<X> const& | |
, boost::fusion::vector<>& | |
) | |
>::type pack; | |
typedef typename boost::fusion::result_of::as_map<pack>::type map_type; | |
typedef parameters<map_type> type; | |
}; | |
template<class X> | |
typename result<X>::type | |
operator[]( param_expr<X> const& xpr ) const | |
{ | |
using boost::fusion::as_map; | |
boost::fusion::vector<> base; | |
typename result<X>::type that(as_map(param_grammar()(xpr,base))); | |
return that; | |
} | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// options entry-point | |
//////////////////////////////////////////////////////////////////////////////// | |
option_binder const options = {}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// User written code begins here | |
/////////////////////////////////////////////////////////////////////////////// | |
BOOST_REGISTER_PARAMETERS(speed); | |
BOOST_REGISTER_PARAMETERS(force); | |
BOOST_REGISTER_PARAMETERS(bar); | |
struct foo | |
{ | |
template <typename ParamMap> | |
foo( ParamMap const& opt ) | |
: speed_( opt(speed) ) | |
, force_( opt(force) ) | |
, bar_( opt(bar, true) ) | |
{} | |
float speed_; | |
int force_; | |
bool bar_; | |
}; | |
struct baz | |
{ | |
template <typename ParamMap> | |
baz( ParamMap const& opt ) | |
: speed_( opt(speed) ) | |
, force_( opt(force) ) | |
, bar_( opt(bar) ) | |
{} | |
float speed_; | |
int force_; | |
bool bar_; | |
}; | |
int main() | |
{ | |
{ | |
foo f(options[speed = 8.9f, bar= false, force = 5]); | |
cout << f.speed_ << " " << f.force_ << " " << f.bar_ << "\n"; | |
} | |
{ | |
foo f(options[speed = 8.9f, force = 5]); | |
cout << f.speed_ << " " << f.force_ << " " << f.bar_ << "\n"; | |
} | |
{ | |
// uncomment this to get an error | |
//baz b(options[speed = 9.9f, force = 5]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment