Boost logo

Boost :

From: jaakko.jarvi_at_[hidden]
Date: 2001-04-06 05:44:26


--- In boost_at_y..., "David Abrahams" <abrahams_at_m...> wrote:
>
> ----- Original Message -----
> From: "Ullrich Koethe" <u.koethe_at_c...>
> > > but it still doesn't handle the const/non-const reference
combinatorics
> > > problem.
> >
> > What exactly is this problem? Can it be solved by explicitly
> > specializing the list() factory?
> >
> > list<Foo &>(aFoo) vs.
> > list<Foo const &>(aFoo)
>
> Sure, but not transparently. Now you're requiring users to name the
full
> type of the parameter when they call the forwarding function.
>

I've used a partial solution to this problem in the tuple library.
It's not transparent, but the client doesn't have to
name the full type either.

For example, when creating tuple objects, the user can state whether
to store the parameters as references or as copies:

int j; A a;
make_tuple(i, a); // creates tuple<int, A>
make_tuple(ref(i), ref(a));; // creates tuple<int&, A&>

The ref function wraps the argument inside a class, which holds a
non-const reference to the orginal object. This class object can
be passed by const reference to some function, and inside the function
the argument can be converted back to a reference to the original
object. This is accomplished by defining a conversion operator for
the wrapper class. Here's some code:

// code --------------------

template<class T>
class reference_wrapper {
  T& x;
public:
  explicit reference_wrapper(T& t) : x(t) {}
  operator T&() const { return x; }
};

template<class T>
inline const reference_wrapper<T> ref(T& t) {
   return reference_wrapper<T>(t);
}

void foo(int & j) { ++j; }

// Think of this as some general purpose wrapping
// function with many parameters
template<class T>
void wrap(const T& t) { foo(t); }

int main() {

   int i = 1;
// wrap(i); // this fails, wrap makes i const
   wrap(ref(i)); // ok

   const int j = 2;
// wrap(ref(j)); // fails, as it should
}

// code ends ----------------------------

In tuple case, I want to dig out the type of the wrapped argument
as well. This can be done with traits templates:

template<class T1>
struct tuple_traits {
  typedef T1 type;
};

template<class T>
struct tuple_traits<reference_wrapper<T> > {
  typedef T& type;
};

template<class T1, class T2>
tuple<tuple_traits<T1>::type, tuple_traits<T2>::type>
make_tuple(const T1& t1, const T2& t2) {
  return
    tuple<tuple_traits<T1>::type, tuple_traits<T2>::type>(t1, t2);
}

Cheers, Jaakko


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