Boost logo

Boost :

Subject: [boost] [scope_exit] capture list syntax for scope_exit and local_function
From: Alexander Nasonov (alnsn_at_[hidden])
Date: 2009-01-14 06:55:03


gmane wrote:
> The following errors were found. Fix them, and submit again:
> You seem to be top-posting. Don't do that.
apparently gmane bug.

Hi,
My current implementation uses ref/cref/val prefixes to pass arguments.
It's not consistent with C++0x lambda capture list syntax.

scope_exit: (ref a)(cref b)(val c)
c++0x: [&a, &b, c]

I have a proof-of-concept implementation for

BOOST_SCOPE_EXIT( (&a)(&b)(c) )
{
  std::cout << a << '\n' << b << '\n' << c << '\n';
}
BOOST_SCOPE_EXIT_END

It does not support passing by reference of classes with overloaded
unary operator& but they are rather rare and we can tell users to
use reference_wrapper to pass them.

Also, it does indirect function call. Gcc 3.4 and 4.2 don't optimize
it away even with -O3 but Intel 10.1 does (though, it generates a body
of the function even with -Os).

What do you think?

#include <iostream>
#include <boost/mpl/if.hpp>
#include <boost/call_traits.hpp>
#include <boost/type_traits/is_function.hpp>

template<class T> inline T& deref(T* p, boost::false_type) { return *p; }
template<class T> inline T& deref(T& r, boost::true_type) { return r; }

void foo(int a, long const b, char const c)
{
  int &a_ref_test();
  int &b_ref_test();
  int c_ref_test();

  typedef boost::is_function<typeof(&a_ref_test)> is_not_ref_0;
  typedef boost::is_function<typeof(&b_ref_test)> is_not_ref_1;
  typedef boost::is_function<typeof( c_ref_test)> is_not_ref_2;

  typedef typeof(deref(&a, is_not_ref_0())) value_t_0;
  typedef typeof(deref(&b, is_not_ref_1())) value_t_1;
  typedef typeof(deref( c, is_not_ref_2())) value_t_2;

  typedef boost::mpl::if_<
    is_not_ref_0,
    boost::call_traits<value_t_0>::param_type,
    value_t_0
>::type param_t_0;

  typedef boost::mpl::if_<
    is_not_ref_1,
    boost::call_traits<value_t_1>::param_type,
    value_t_1
>::type param_t_1;

  typedef boost::mpl::if_<
    is_not_ref_2,
    boost::call_traits<value_t_2>::param_type,
    value_t_2
>::type param_t_2;

  struct params_t {
    value_t_0 &a;
    value_t_1 &b;
    value_t_2 c;

    params_t(param_t_0 &a, param_t_1 &b, param_t_2 c)
      : a(a), b(b), c(c)
    {}

    void invoke(void (*f)(param_t_0 &a, param_t_1 &b, param_t_2 c))
    {
      f( deref(&a, is_not_ref_0()),
         deref(&b, is_not_ref_1()),
         deref( c, is_not_ref_2())
       );
    }
  };

  params_t params(
      deref(&a, is_not_ref_0()),
      deref(&b, is_not_ref_1()),
      deref( c, is_not_ref_2())
    );
  void* p = ¶ms;

  struct guard_t {
    params_t* params;

    guard_t(void* p)
      : params((params_t*)p)
    {}

    ~guard_t()
    {
      params->invoke(&guard_t::body);
    }

    static void body(param_t_0 &a, param_t_1 &b, param_t_2 c)
    {
      std::cout << a << '\n' << b << '\n' << c << '\n';
    }
  } guard(p);
}

int main()
{
  foo(0, 1, '2');
}

Thanks,
Alex


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