|
Boost Users : |
Subject: Re: [Boost-users] [PROTO] Custom functions, scalar terminal and make_expr vs details::as_expr_if
From: Eric Niebler (eric_at_[hidden])
Date: 2008-11-29 16:01:59
Joel Falcou wrote:
> I have a large number of custom unary and bin ary function that I map
> using unary_expr and binary_expr.
> The problem is the following : my grammar has integral or floating point
> scalar terminal.
> So, when I want to create a binary function that takes any elements of
> my domain, I'm boudn to do the following :
>
> template<class L,class R>
> typename result_of::make_expr<....>::type
> my_custom_binary_func( L const& l, R const& r )
> {
> return make_expr( ... );
> }
>
> Alas, as I already discussed with Eric, nothign prevent me to use
> my_custom_binary_func over types
> that aren't in my grammar.
The first question to ask is if it is really absolutely necessary to
prevent users from creating invalid expressions with
my_custom_binary_func(), or if you can catch the error someplace else;
e.g., when users try to evaluate the expression. Reporting a hard error
later can often yield a better error message then using SFINAE to prune
overload sets earlier.
> To do so, I was told to use SFINAE to prune
> unwanted element by matching the result type
> of make_expr on my grammar. However, this proves cumbersome and slow
> down compile time by *a large factor* when
> I have a large number of such function (and I have like 50 or 60).
>
> So i wandered into proto source code and looked at how proto solves this
> problem for its binary operator.
> This solution seems more elegant but as it live sin proto::detail, I
> don't think I'm intended to use it.
>
> So, how can I have a simple and fast creation of custom expression ? Am
> I missing something blatant ?
If you really want to prevent users from creating invalid expressions
with these functions, you can do something like the following ...
template<typename T>
struct valid_terminal {}; // empty!
template<>
struct valid_terminal<int> { typedef int type; };
// other specializations for valid terminal types ...
// When L and R are both proto expressions
template<class L,class R>
typename result_of::make_expr<
my_custom_binary_tag
, my_domain
, typename L::proto_derived_type const &
, typename R::proto_derived_type const &
>::type
my_custom_binary_func( L const& l, R const& r ) { /*...*/ }
// When L is a proto expression and R is a terminal
template<class L,class R>
typename result_of::make_expr<
my_custom_binary_tag
, my_domain
, typename L::proto_derived_type const &
, typename valid_terminal<R>::type const &
>::type
my_custom_binary_func( L const& l, R const& r ) { /*...*/ }
// When R is a proto expression and L is a terminal
template<class L,class R>
typename result_of::make_expr<
my_custom_binary_tag
, my_domain
, typename valid_terminal<L>::type const &
, typename R::proto_derived_type const &
>::type
my_custom_binary_func( L const& l, R const& r ) { /*...*/ }
// When L and R are valid terminal types
template<class L,class R>
typename result_of::make_expr<
my_custom_binary_tag
, my_domain
, typename valid_terminal<L>::type const &
, typename valid_terminal<R>::type const &
>::type
my_custom_binary_func( L const& l, R const& r ) { /*...*/ }
If you want to improve compile times even more, you can avoid make_expr
entirely and code by-hand what make_expr would do. So, e.g., the second
overload above would be:
// When L is a proto expression and R is a terminal
template<class L,class R>
my_expr_wrapper<
proto::expr<
my_custom_binary_tag
, proto::list2<
typename L::proto_derived_type const &
my_expr_wrapper<
proto::expr<
proto::tag::terminal
, proto::term<
typename valid_terminal<R>::type const &
>
>
>
>
>
>
my_custom_binary_func( L const& l, R const& r ) { /*...*/ }
And in the body of my_custom_binary_func() you initialize an object of
this type directly instead of calling make_expr(). Naturally, you'd put
all this gunk in a macro so you can easily define all 50 or so of your
custom binary functions.
Note that I don't think this solution is particularly better than just
letting my_custom_binary_func create invalid expressions and catching
the mistake later.
HTH,
-- Eric Niebler BoostPro Computing http://www.boostpro.com
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net