Boost logo

Boost :

From: Ion Gaztañaga (igaztanaga_at_[hidden])
Date: 2008-08-10 08:09:31


Hi to all,

These days I've been thinking about adding perfect forwarding benefits
to Boost Interprocess:

1)Adding "emplace" functions to containers

2)Interprocess has several functions taking an "arbitrary" number of
parameters (e.g.: to construct an object in shared memory forwarding all
constructor parameters).

Currently, I've just used the preprocessor or manual repetition to
implement some of those features, but now I want to take advantage of
compilers (such as gcc 4.3 with -std=gnu++0x) that have both rvalue
references and variadic templates.

One solution would be write new functions with variadic templates, just
as most containers use templatized range insertion functions.

One option to avoid code duplication between range and emplace code is
just to pack both range insertion and variadic construction logic in a
function object that packs the needed code (function) and data
(arguments). However, I also want to minimize both compilation time and
code size. This can be achieved encapsulating those object function
calls behind virtual functions, so that the main code is not heavily
templatized and calls virtual functions that perform the parameter
dependent job. An example:

class container
{
    struct insert_callbacks
    { //One possible callback
       virtual copy_all_to_pos(iterator pos) = 0;
    }

    template<class FwdIt>
    struct fwd_it_callbacks
       : public insert_callbacks
    {
       fwd_it_callbacks(FwdIt first, FwdIt last)
          : first_(first), last_(last)
       {}

       virtual copy_all_to_pos(iterator pos)
       { std::copy(first, last, pos); }
       private:
       FwdIt first_, last_;
    }

    template<class ...Args>
    struct emplace_callbacks
       : public insert_callbacks
    {
       emplace_callbacks(Args&& ...args)
          : packed_args_(args...)
       {}

       virtual copy_all_to_pos(iterator pos)
       {
          *pos = T(unpack_somehow(packed_args_));
       }
       private:
       something_to_pack packed_args_;
    }

    template<class FwdIt>
    void insert(iterator pos, FwdIt first, FwdIt last)
    {
       this->insert_impl(pos, fwd_it_callbacks(first, last);
    }

    template<class ...Args>
    void insert(iterator pos, Args &&...args)
    {
       this->insert_impl
          (pos, insert_callbacks(std::forward<Args>(args)...);
    }

    void insert_impl(iterator pos, insert_callbacks &cb)
    {
        //Make room for new data
        //...
        //Prepare exception handling rollbacks..
        //...
        //Call, input-dependent code:
        cb.copy_all_to_pos(pos);

        //More code
        //...
    }
};

Using this approach insert_impl avoids template arguments, generating
exactly the same code for all foward iterator types and emplace
functions. However, we need a function object that somehow packs
arguments and forwards them perfectly to implement emplace functions
this way.

Since bind() copies arguments (and boost::bind does not use variadic
templates yet) and reference_wrapper does not support rvalue references
(at least not the latest std draft n2691), I've just started playing
with gcc and using Doug Gregor's variadic templates papers' code. I've
come up with a solution but that does of calling another function
passing the arguments perfectly (code attached).

You can use std::tr1::tuple to pack references and the expansion
operator (...) to convert those packed arguments again to a function
call. In the attached code we can avoid using std::tr1::tuple with a
define (a compiler might have perfect forwarding but maybe the standard
library is not updated yet, so I shouldn't rely on std::tr1::tuple).

All this effort has been very useful to me to start playing with
variadic templates, tuples, etc... but I think many boost library
implementers will try to do something similar (perfect forwarding
through an object function) in the future. The aim of this post is to
know if any other boost library writer is playing with variadic
templates and he/she has solved this issue in a simpler way.

Regards,

Ion

P.S.: To compile attached code you need gcc 4.3 and activate c++0x support.




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