|
Boost : |
From: Joel de Guzman (joel_at_[hidden])
Date: 2006-05-11 19:27:06
Tobias Schwinger wrote:
> Joel de Guzman wrote:
>> Tobias Schwinger wrote:
>>
>>> Tobias Schwinger wrote:
>>
>>>> I'm still playing with it and hope I can add some details here, soon.
>>>>
>>> I wanted to use Fusion to write something (well, at least half-way)
>>> real for review, so I chose to solve this problem:
>>>
>>> Call one of a heterogenous set of functors (their call operators might
>>> be templates) based on a runtime index with a complexity of O(log N)
>>> (basically what an n-ary tree structure of nested switch/case blocks
>>> does).
>>>
>>> The solution
>>> o handles unary functors only and doesn't bother with the result (simplicity),
>>> o contains numerous workarounds and is far away from being perfect,
>>> o requires an MPL-patch [ http://tinyurl.com/ljfdm] to compile, but
>>> o nevertheless documents my fight with the library, hopefully including
>>> lots of mistakes a new user is tempted to make, so it might work good to
>> inspire upcomnig examples.
>>
>>> http://tinyurl.com/l5bxl (source file in the vault)
>>
>> Very cool! That might be a good example for a tutorial if you are
>> willing to document and share it.
>
> Sure (that is, for the willingness-part).
>
> I'm not sure whether it qualifies for a good tutorial. There might be better ways
> to do things (I wanted to get my hands on the library quickly, so I didn't put too
> much time into planning, plus I still have some questions, below).
Right.
> Given that my implementation can not be radically simplified, it might also be too
> much code for a tutorial. Maybe a linear version for a tutorial and the logarithmic
> version for an inline-documented source code example would work better...
>
> BTW. implementation improvements, anyone? I'm all ear!
I was contemplating on something like the one you are doing.
The inputs are:
1) A runtime value (a primitive integer; e.g. char,int)
2) A tuple of functions
3) A tuple of args (usually tiers)
I was thinking of using the boost preprocessor instead to
generate actual switch code. Something like:
template <int Size>
struct switch_dispatch;
template <>
struct switch_dispatch<1>
{
template <typename RT, typename Int
, typename Functions, typename Args>
static RT
call(int n, Functions const& dispatch, Args const& args)
{
return at_c<0>(dispatch)(args);
}
};
template <>
struct switch_dispatch<2>
{
template <typename RT, typename Int
, typename Functions, typename Args>
static RT
call(int n, Functions const& dispatch, Args const& args)
{
if (n == 0)
return at_c<0>(dispatch)(args);
else
return at_c<1>(dispatch)(args);
}
};
template <>
struct switch_dispatch<3>
{
template <typename RT, typename Int
, typename Functions, typename Args>
static RT
call(int n, Functions const& dispatch, Args const& args)
{
switch (n)
{
case 0: return at_c<0>(dispatch)(args);
case 1: return at_c<1>(dispatch)(args);
}
}
};
++ A little change, we can use an mpl::vector_c to hold the cases.
Something like:
case mpl::at_c<cases, 0>::value : return at_c<0>(dispatch)(args);
case mpl::at_c<cases, 1>::value : return at_c<1>(dispatch)(args);
where "cases" is an mpl::vector_c. Such a utility will provide the
backbone for 1) Phoenix2's switch_ statement 2) Spirit's switch_p
3) Spirit-2's predictive parsing schemes, and all those stuff that
intends to optimize spirit's alternative.
++ Some more code to handle defaults; etc... see Phoenix2 switch
and Spirit switch_p for reference.
... More comments on your post later.
Regards,
-- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk