Boost logo

Boost :

From: ION_G_M (ION_G_M_at_[hidden])
Date: 2005-02-18 07:29:04


Hello to all,

 while developing Boost Shmem, I wanted to create a constructor proxy
to emulate c++ dynamic object allocation syntax when creating shared
memory objects using a proxy object in the following way:

 T * ptr = shmem_segment.create<T>("ObjectName")[size]
           /*proxy returned here, calls operator() of the object*/
           (arg1, arg2, ...argN);

Shared memory is allocated and the object is constructed. I want the
arguments to be deduced automatically in the proxy object function call
to preserve this syntax. I also want to avoid _all_ parameter copying.
I mean, if I can deduce that an argument can be passed by value or by
referenced using this syntax, great. But, between copying _all_
arguments and passing a reference in _all_, I prefer the second.

 Trying to find a correct proxy for this, I had many problems when
passing temporary arguments and hardcoded constants to the proxy. Right
now I am using some ugly casts to avoid the copies, but this has some
side-effects. I will explain the problem in the following code:

 
#include <new>

//Object to be constructed
struct Ctor2Arg
{
   Ctor2Arg(const int &const_ref, int &non_const_ref){}
};

//"Clean" proxy
template <class T>
struct constructor_proxy_t
{
   template<class T0, class T1>
   void operator()(T0 & t0, T1 & t1) const
   {
      char m_mem[sizeof(T)];
      //Call constructor and destructor
      T *ptr = new(m_mem)T(t0, t1);
      ptr->~T();
   }
};

//Ugly cast proxy
template <class T>
struct ugly_constructor_proxy_t
{
   template<class T0, class T1>
   void operator()(const T0 & t0, const T1 & t1) const
   {
      char m_mem[sizeof(T)];
      //Convert all refs to non-const refs
      T0 & t0ref = const_cast<T0 &>(t0);
      T1 & t1ref = const_cast<T1 &>(t1);
      //Call constructor and destructor, non-const
      //refs can be converted to const refs
      T *ptr = new(m_mem)T(t0ref, t1ref);
      ptr->~T();
   }
};

//Main function
int main()
{
   //Construct normal and ugly proxies
   constructor_proxy_t<Ctor2Arg> proxy;
   ugly_constructor_proxy_t<Ctor2Arg> ugly_proxy;

   //One const int and one non-const int
   const int dummy_const = 0;
   int dummy_non_const = 0;

   //This is ok, calls:
   //constructor_proxy_t<Ctor2Arg>::operator()
   //<int const ,int>(const int & t0=0, int & t1=0)
   proxy(dummy_const, dummy_non_const);

   //Both of these calls do not compile in VC7.1 or gcc 3.4.3,
   //tries to call constructor_proxy_t<Ctor2Arg>::operator()
   //<int, int>(int & t0=5, int & t1=0)
   //
   // gcc 3.4.3 error
   //
   //error: no match for call to
   // `(constructor_proxy_t<Ctor2Arg>) (int, int&)'
   //candidates are:
   // void constructor_proxy_t<T>::operator()(T0&, T1&)
   // [with T0 = int, T1= int, T = Ctor2Arg]
   //
   //Obviously, compilers are right, but
   //it wouldn't be more logical to call
   //<int const, int> specialization since a
   //temporary is a constant object?
// proxy(dummy_non_const+5, dummy_non_const);
// proxy(dummy_const+5, dummy_non_const);

   //This is ok, calls:
   //ugly_constructor_proxy_t<Ctor2Arg>::operator()
   //<int,int>(const int & t0=0, const int & t1=0)
   ugly_proxy(dummy_const, dummy_non_const);

   //These are ok, call:
   //ugly_constructor_proxy_t<Ctor2Arg>::operator()
   //<int,int>(const int & t0=5, const int & t1=0)
   ugly_proxy(dummy_non_const+5, dummy_non_const);
   ugly_proxy(dummy_const+5, dummy_non_const);

   //This compiles but it should not, since
   //I am passing a const object as second parameter
   //so Ctor2Arg obj(dummy_const, dummy_const)
   //does not compile. This calls:
   //ugly_constructor_proxy_t<Ctor2Arg>::operator()
   //<int,int>(const int & t0=0, const int & t1=0)
   ugly_proxy(dummy_const, dummy_const);

   return 0;
}

 My question is, has anyone a better way to write the proxy object
without ugly casts, no side-effects (I mean, the proxy call should
compile only if the constructor compiles), preserving a clean calling
syntax, and _no_ object copies at all?

 And the second question is: when a temporary is passed to a template,
why non-const argument is deduced in the function call?

Thank you, regards,

/Ion


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