Le 10/04/12 02:10, Jeffrey Lee Hellrung, Jr. a écrit :
On Mon, Apr 9, 2012 at 4:54 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 10/04/12 01:24, Jeffrey Lee Hellrung, Jr. a écrit :
On Mon, Apr 9, 2012 at 3:14 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:



The overload

        explicit packaged_task(R(*f)()):
            task(new detail::task_object<R,R(*)()>(f)),future_obtained(false)
        {}

seems necessary because otherwise the task_object is instantiated with <R,R()> which is not what we want.
Do you have an hint on how simplify this?

Okay yeah I wasn't sure why you needed this overload, thanks for clarifying. I guess when constructing a packaged_task with a function name, and you don't explicitly use the address-of operator (&), F gets bound as a function reference? Probably easiest to just explicitly use a separate constructor as above and document its necessity.


The test futures/packaged_task/alloc_ctor_pass.cpp gives this context.

Thanks for your patience and perseverance.

And thank you for clarifying the issue for me!


Please, could you check the patch and see if there is something that can be improved.

Yeah that looks about what I would've suggested. Just add, like you said, the remove_cv's.


I have added some test for const and free functions.

Note, as you mentioned, the need to use & in (***1) when the function doesn't returns the packaged_task result type but something convertible to it.

With the following patch everything is OK.

It is a pleasure to work with you. I learn always something important :-)
Vicente

===============================================
tests
===============================================

double fct()
{
  return 5.0;
}
long lfct()
{
  return 5;
}

  {
      const A a(5);
      boost::packaged_task<double> p(a);
      BOOST_TEST(p.valid());
      boost::future<double> f = BOOST_EXPLICIT_MOVE(p.get_future());
      //p(3, 'a');
      p();
      BOOST_TEST(f.get() == 5.0);
      BOOST_TEST(A::n_copies > 0);
      BOOST_TEST(A::n_moves > 0);
  }
  {
      boost::packaged_task<double> p(fct);
      BOOST_TEST(p.valid());
      boost::future<double> f = BOOST_EXPLICIT_MOVE(p.get_future());
      //p(3, 'a');
      p();
      BOOST_TEST(f.get() == 5.0);
  }
  {
      boost::packaged_task<double> p(&lfct); // *** 1
      BOOST_TEST(p.valid());
      boost::future<double> f = BOOST_EXPLICIT_MOVE(p.get_future());
      //p(3, 'a');
      p();
      BOOST_TEST(f.get() == 5.0);
  }

===============================================
patch
===============================================

Index: boost/thread/future.hpp
===================================================================
--- boost/thread/future.hpp    (revision 77875)
+++ boost/thread/future.hpp    (working copy)
@@ -20,6 +20,7 @@
 #include <boost/type_traits/is_fundamental.hpp>
 #include <boost/type_traits/is_convertible.hpp>
 #include <boost/type_traits/remove_reference.hpp>
+#include <boost/type_traits/remove_cv.hpp>
 #include <boost/mpl/if.hpp>
 #include <boost/config.hpp>
 #include <boost/throw_exception.hpp>
@@ -1811,7 +1812,9 @@
 #ifndef BOOST_NO_RVALUE_REFERENCES
         template <class F>
         explicit packaged_task(F&& f):
-            task(new detail::task_object<R,typename remove_reference<F>::type>(boost::forward<F>(f))),future_obtained(false)
+            task(new detail::task_object<R,
+                typename remove_cv<typename remove_reference<F>::type>::type
+                >(boost::forward<F>(f))),future_obtained(false)
         {}
 #else
         template <class F>
@@ -1832,11 +1835,22 @@
 #endif
 
 #if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS
+        template <class Allocator>
+        packaged_task(boost::allocator_arg_t, Allocator a, R(*f)())
+        {
+          typedef R(*FR)();
+          typedef typename Allocator::template rebind<detail::task_object<R,FR> >::other A2;
+          A2 a2(a);
+          typedef thread_detail::allocator_destructor<A2> D;
+
+          task = task_ptr(::new(a2.allocate(1)) detail::task_object<R,FR>(f), D(a2, 1) );
+          future_obtained = false;
+        }
 #ifndef BOOST_NO_RVALUE_REFERENCES
         template <class F, class Allocator>
         packaged_task(boost::allocator_arg_t, Allocator a, F&& f)
         {
-          typedef typename remove_reference<F>::type FR;
+          typedef typename remove_cv<typename remove_reference<F>::type>::type FR;
           typedef typename Allocator::template rebind<detail::task_object<R,FR> >::other A2;
           A2 a2(a);
           typedef thread_detail::allocator_destructor<A2> D;