Boost logo

Boost :

Subject: Re: [boost] [local] Help for the Alternatives section
From: lcaminiti (lorcaminiti_at_[hidden])
Date: 2011-05-05 13:53:10


lcaminiti wrote:
>
>
> Mathias Gaunard-2 wrote:
>>
>> On 03/05/2011 21:44, lcaminiti wrote:
>>> Is there a way to do this or something similar with Boost.Phoenix (or
>>> Boost.Lambda)?
>>
>> std::vector<double> v(3);
>> std::for_each(v.begin(), v.end(), ref(sum) += factor * _1);
>>
>> std::vector<int> w(3);
>> std::for_each(w.begin(), w.end(), ref(sum) += factor * _1);
>>
>> or if you want to avoid repetition,
>>
>> auto local_add = ref(sum) += factor * _1;
>>
>> std::vector<double> v(3);
>> std::for_each(v.begin(), v.end(), local_add);
>>
>> std::vector<int> w(3);
>> std::for_each(w.begin(), w.end(), local_add);
>>
>> Note you need auto, since using type erasure would force the function
>> object to be monomorphic.
>>
>
> I think I can do this also without auto so it compiles on ISO C++. The
> following works (even if the type expression that replaces auto is very
> ugly -- perfect example of why C++0x's auto is useful):
>
> #include &lt;boost/spirit/include/phoenix.hpp&gt;
> #include <iostream>
> #include <vector>
>
> int main() {
> using boost::phoenix::arg_names::_1;
>
>
> boost::phoenix::actor&lt;boost::phoenix::composite&lt;boost::phoenix::shift_left_eval,
> boost::fusion::vector&lt;boost::phoenix::composite&lt;boost::phoenix::shift_left_eval,
> boost::fusion::vector&lt;boost::phoenix::reference&lt;std::basic_ostream&lt;char,
> std::char_traits&lt;char&gt; > >, boost::phoenix::argument<0>,
> boost::fusion::void_, boost::fusion::void_, boost::fusion::void_,
> boost::fusion::void_, boost::fusion::void_, boost::fusion::void_,
> boost::fusion::void_, boost::fusion::void_> >, boost::phoenix::value<const
> char*>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_,
> boost::fusion::void_, boost::fusion::void_, boost::fusion::void_,
> boost::fusion::void_, boost::fusion::void_> > >
> f = std::cout << _1 << "\n";
>
> std::vector<double> v(3);
> v[0] = -1.0; v[1] = -2.0; v[2] = -3.0;
> std::for_each(v.begin(), v.end(), f);
>
> std::vector<std::string> s(3);
> s[0] = "aa"; s[1] = "bb"; s[2] = "cc";
> std::for_each(s.begin(), s.end(), f);
>
> return 0;
> }
>
> This does what I was looking for:
> 1) Compiles on ISO C++.
> 2) Declares f locally (information hiding).
> 3) Does not repeat f declaration multiple times (avoid code duplication).
> 4) f is polymorphic in its argument type _1 (it accepts both doubles and
> std::strings).
>
> I am thinking that I will add the monomorphic (Boost.Local, Local
> Functors, and C++0x lambdas*) vs. polymorphic (Boost.Phoenix, Boost.Local,
> and Global Functors) comparison to the Alternatives section.
>
> (*) BTW, as I understand it, C++0x lambdas are monomorphic in their
> argument types -- correct?
>

I have been thinking if I can do something similar to this with Boost.Local.
Given that local classes cannot have template members I can't do too much...
However, I _could_ allow to specify multiple types (but not a generic type)
for a local function parameter:

void BOOST_LOCAL_FUNCTION_PARAMS(types(int, char) x, types(double,
std::string, int) y, long z) {
    std::cout << x << y << z << std::endl;
} BOOST_LOCAL_FUNCTION_NAME(l)

Then I can do:

l(1, 1.2, -1);
l('a', 1.2, -1);
l('a', "bcd", -1);
... // and all the other parameter type combinations

types(...) could accept a generic number of types but all these types will
have to be known (and not generic as for templates).

With this, the Boost.Phoenix example above will look like the following in
Boost.Local:

#include &lt;boost/local/fuction.hpp&gt;
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    void BOOST_LOCAL_FUNCTION_PARAMS(
            // Accepts both double and std::string.
            types(const double&, const std::string&) num) {
        std::cout << num << std::endl;
    } BOOST_LOCAL_FUNCTION_NAME(l)

    std::vector<double> v(3);
    v[0] = -1.0; v[1] = -2.0; v[2] = -3.0;
    std::for_each(v.begin(), v.end(), l); // Call passing double.

    std::vector<std::string> s(3);
    s[0] = "aa"; s[1] = "bb"; s[2] = "cc";
    std::for_each(s.begin(), s.end(), l); // Call passing std::string.

    return 0;
}

This is more overloading than polymorphism... bus still:
1) Compiles on ISO C++.
2) Declares l locally (information hiding).
3) Does not repeat l declaration multiple times (avoid code duplication).
4) l is """effectively polymorphic""" (in between _many_ quotes :) ) in its
argument type num as it accepts both doubles and std::strings (but no more
than these two types :( ). (I will not actually claim that such a local
function l polymorphic in num's type.)

What do you think?

Thanks,
--Lorenzo

--
View this message in context: http://boost.2283326.n4.nabble.com/local-Help-for-the-Alternatives-section-tp3408469p3499021.html
Sent from the Boost - Dev mailing list archive at Nabble.com.

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk