On Mon, Apr 9, 2012 at 3:14 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 09/04/12 20:06, Jeffrey Lee Hellrung, Jr. a écrit :
On Mon, Apr 9, 2012 at 10:41 AM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 08/04/12 17:18, Jeffrey Lee Hellrung, Jr. a écrit :
On Sun, Apr 8, 2012 at 5:46 AM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:

After the commit some error have appeared on the regression test (see below). It seems that the rvalue reference semantic has changed a lot for gcc. I will try to use the last design for this compiler version. Then I'll see what needs to be done for other compilers as soon as results appear on the regression tests page.

TBH, I wasn't really sure exactly what problem you were trying to address with that patch, and how it addressed that :/ Care to recap?

Note that I think we have 2 threads here on Boost.Thread, one regarding VS 2010 and one regarding Sun. I might be getting them confused.

Hi,

Sorry for all this noise.

No problem! I just want to be sure we're on the same page. I'm not very familiar with the thread library but I thought I could contribute to this problem in some way :/

I'm replaying to the error signaled on this thread and it concerns VS 2010 (not Sun) and concerns also other compilers (in particular I tested the example below with clang 3.0, gcc-4.6.2,4.7.0)

The signaled error was

E:\boost_1_49\boost/thread/future.hpp(1251): error C2535: 'boost::detail::task_object<R,F>::task_object(F)' : member function already defined or declared
          with
          [
              R=size_t,
              F=std::tr1::_Bind<size_t,size_t,std::tr1::_Bind1<std::tr1::_Callable_fun<size_t (__cdecl *const )(std::string &),false>,const char *>> &
          ]
          E:\boost_1_49\boost/thread/future.hpp(1247) : see declaration of 'boost::detail::task_object<R,F>::task_object'
          with
          [
              R=size_t,
              F=std::tr1::_Bind<size_t,size_t,std::tr1::_Bind1<std::tr1::_Callable_fun<size_t (__cdecl *const )(std::string &),false>,const char *>> &
          ]

The concerned code is
        template<typename R,typename F>
        struct task_object:
            task_base<R>
        {
            F f;
            task_object(F const& f_):
                f(f_)
            {}
            task_object(F&& f_):
                f(f_)
            {}
    template<typename R>
    class packaged_task
    {
        template <class F>
        explicit packaged_task(F const& f):
            task(new detail::task_object<R,F>(f)),future_obtained(false)
        {}
        explicit packaged_task(R(*f)()):
            task(new detail::task_object<R,R(*)()>(f)),future_obtained(false)
        {}
        template <class F>
        explicit packaged_task(F&& f):
            task(new detail::task_object<R,F>(f)),future_obtained(false) // *** 1
        {}

I think the error comes from the following line in the example (see ***2 below)

 async_func_pt<RetType>* p= new  async_func_pt<RetType> (boost::packaged_task<RetType>(f));

that should forward the reference while passing f.

 async_func_pt<RetType>* p= new  async_func_pt<RetType> (boost::packaged_task<RetType>(std::forward<F>(f)));

because otherwise I believe the deduced template type is F&. Am I right?

I think you're (partially) right.
 
When F& was given to the constructor of packaged_task it instantiated task_object<R,F&>
As the same error were in the the Boost.Thread code in (1) above. The use of forward solves the issue

            task(new detail::task_object<R,F>(boost::forward<F>(f))),future_obtained(false) // *** 1

So the instantiated constructors were

            task_object( const F& & f_):
                f(f_)
            {}
            task_object(F& && f_):
                f(f_)
            {}

which produced the ambiguity.

Agreed.

There are yet some problems on the Boost.Thread implementation or with the compilers implementation.

When I want to pass functor, as in

A a(5);
boost::packaged_task<int> pt(a);

the constructor used is packaged_task(F&& f) and I will expect packaged_task(F const& f) to be use for.
Are my expectations correct?

Well...no, apparently your expectations are not correct. But that's slightly beside the point. I think the correct fix here is to remove the packaged_task(F const &) overload entirely, since the packaged_task(F&&) overload already covers it (that's part of the entire design of "templated rvalue references", to capture both rvalues *and* lvalues). Then instantiate task_object with something like remove_cv< remove_reference<F>::type >::type, and use boost::forward<F>(f) to pass the function object down to the task_object constructor.

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!

Best,
Vicente

P.S. I have committed the example as test_ml.cpp with some modifications.
I have rolled back the code adding the forward calls and I'll commit it in trunk as sonn as the whole regression works on all the compiler I can test.

======================================================
#include "boost/test/unit_test.hpp"
#include "boost/thread/future.hpp"
#include "boost/utility/result_of.hpp"
#include <functional>

struct async_func {
    virtual ~async_func() { }
    virtual void run() =0;
    };

template <typename Ret>
class async_func_pt : public async_func {
    boost::packaged_task<Ret> f;
public:
    void run() override { f(); }
    async_func_pt (boost::packaged_task<Ret>&& f) : f(std::move(f)) {}
    ~async_func_pt() { }
    boost::unique_future<Ret> get_future()  { return f.get_future(); }
    };

void async_core (async_func* p);




template <typename F>
boost::unique_future<typename boost::result_of< F() >::type>
async (F&& f)
 {
 typedef typename boost::result_of< F() >::type RetType;
 async_func_pt<RetType>* p= new  async_func_pt<RetType> (boost::packaged_task<RetType>(f)); // ***2
 boost::unique_future<RetType> future_result= p->get_future();
 async_core (p);
 return std::move(future_result);
 }

template <typename F, typename A1>
boost::unique_future<typename boost::result_of< F(A1) >::type>
async (F&& f, A1&& a1)
 {
// This should be all it needs.  But get a funny error deep inside Boost.
// problem overloading with && ?
 return async (std::tr1::bind(f,a1));
 }

BOOST_AUTO_TEST_SUITE(thread_pool_tests)

int calculate_the_answer_to_life_the_universe_and_everything()
{
    return 42;
}


size_t foo (const std::string& s)
 {
 return s.size();
 }



BOOST_AUTO_TEST_CASE( async_test )
{
// this one works
    // most fundimental form:
    boost::unique_future<int> fi= async (&calculate_the_answer_to_life_the_universe_and_everything);
    int i= fi.get();
    BOOST_CHECK_EQUAL (i, 42);


// This one chokes at compile time
    boost::unique_future<size_t> fut_1= async (&foo, "Life");

    BOOST_CHECK_EQUAL (fut_1.get(), 4);
}


BOOST_AUTO_TEST_SUITE_END()

_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users