Opened 9 years ago

Closed 9 years ago

#9303 closed Bugs (worksforme)

packaged_task<R(Argtypes)> does not compile using c++03 and Cmake 2.8.9

Reported by: e66a5b10@… Owned by: viboes
Milestone: Component: thread
Version: Boost 1.54.0 Severity: Problem
Keywords: packaged_task, bind, asio Cc:

Description

Setup consists of client(s), a server, and device(s).

A client interacts with a device by sending requests to the server. These requests are examined and routed to the appropriate device. Requests are handled asynchronously, and are occasionally queued up via boost::asio::io_service::strand for various reasons.

It appears as if packaged_task has a few different templates to choose from:

packaged_task<R> packaged_task<R()> packaged_task<R(ArgTypes)>

To ensure that I was using the function correctly, I started simple; using the simple example on the boost::futures page as a starting point. From there, I created four simple functions:

int return, no parameters. int return, with parameters. std::string return, no parameters. std::string return, with parameters. Test functions

std::string ans("forty two");

int int_no_params()
{
    return 42;
}

int int_with_params(int param)
{
    return param;
}

std::string string_no_params()
{
    return std::string("forty two");
}

std::string string_with_params(std::string & param) // Have tried both with and without '&'
{
    return param;
}


EXAMPLE 1:

int function(void)

    //! Compiles and produces correct result.  
    {
        boost::packaged_task<int()> example(int_no_params);
        boost::future<int> f = example.get_future();
        boost::thread task(boost::move(example));
        int answer = f.get();
        std::cout << "Answer to life and whatnot, in English: " << answer << std::endl;
        task.join();
    }

EXAMPLE 2:

std::string function(void)

    //! Compiles and produces correct result.
    {
        boost::packaged_task<std::string()> example(string_no_params);
        boost::future<std::string> f = example.get_future();
        boost::thread task(boost::move(example));
        std::string answer = f.get();
        std::cout << "string_no_params: " << answer << std::endl;
        task.join();
    }

EXAMPLE 3:

std::string(std::string& param) No threading

//! Doesn't compile.
//! error: variable ‘boost::packaged_task<std::basic_string<char>(std::basic_string<char>&)> example’ has initializer but incomplete type

{
    boost::packaged_task<std::string(std::string&)> example(string_with_params);
    boost::future<std::string> f = example.get_future();
    example(ans);
    std::string answer = f.get();
    std::cout << "string_with_params: " << answer << std::endl;
}

EXAMPLE 4:

using boost::threading

//! Doesn't compile.
//! error: variable ‘boost::packaged_task<std::basic_string<char>(std::basic_string<char>&)> example’ has initializer but incomplete type
{
    boost::packaged_task<std::string(std::string&)> example(string_with_params);
    boost::future<std::string> f = example.get_future();
    boost::thread task(boost::move(example), ans);
    std::string answer = f.get();
    std::cout << "string_with_params: " << answer << std::endl;
    task.join();
}

EXAMPLE 5:

//Using extended initializers in packaged_task declaration

//! Doesn't compile in C++03, C++11 only.
//! error: extended initializer lists only available with -std=c++11 or -std=gnu++11 [-Werror]
{
    boost::packaged_task<std::string(std::string&)> example
    { boost::bind(&string_with_params, ans) };
    boost::future<std::string> f = example.get_future();
    boost::thread task(boost::move(example), ans);
    std::string answer = f.get();
    std::cout << "string_with_params: " << answer << std::endl;
    task.join();
}

EXAMPLE 6:

//Threaded, using shared_ptr

//The following use typedef boost::packaged_task<std::string(std::string&)> task_t;

//Because packaged tasks can't be copied, binding 
//shared_ptr<T>::operator() to task was a suggested solution found on stackoverflow.

// error: invalid use of incomplete type ‘class boost::packaged_task<std::basic_string<char>(std::basic_string<char>&)>’
// error: incomplete type ‘task_t {aka boost::packaged_task<std::basic_string<char>(std::basic_string<char>&)>}’ used in nested name specifier
// boost/thread/future.hpp:1320:11: error: declaration of ‘class boost::packaged_task<std::basic_string<char>(std::basic_string<char>&)>’
{
    boost::shared_ptr<task_t> example = boost::make_shared<task_t>(boost::bind(&string_with_params, ans));
    boost::future<std::string> f = example->get_future();
    boost::thread task(boost::bind(&task_t::operator(), example));
    std::string answer = f.get();
    std::cout << "string_with_params: " << answer << std::endl;
    task.join();
}

EXAMPLE 7:

//Using boost::asio::io_service and boost::bind

// error: invalid use of incomplete type ‘class boost::packaged_task(std::basic_string&)>’ // error: incomplete type ‘task_t {aka boost::packaged_task(std::basic_string&)>}’ used in nested name specifier // boost/thread/future.hpp:1320:11: error: declaration of ‘class boost::packaged_task(std::basic_string&)>’

{
    boost::asio::io_service io_service;
    boost::thread_group threads;
    boost::asio::io_service::work work(io_service);

    for (int i = 0; i < 3; ++i)
    {
        threads.create_thread(boost::bind(&boost::asio::io_service::run,
            &io_service));
    }

    boost::shared_ptr<task_t> example = boost::make_shared<task_t>(boost::bind(&string_with_params, ans));
    boost::future<std::string> f = example->get_future();
    io_service.post(boost::bind(&task_t::operator(), example));
    std::string answer = f.get();
    std::cout << "string_with_params: " << answer << std::endl;
    threads.join_all();
}

It seems like future.hpp has a problem that is preventing the proper template from being used.

Attachments (1)

packagedTestTest.cpp (5.8 KB ) - added by anonymous 9 years ago.

Download all attachments as: .zip

Change History (8)

by anonymous, 9 years ago

Attachment: packagedTestTest.cpp added

comment:1 by viboes, 9 years ago

Owner: changed from Anthony Williams to viboes
Status: newassigned

This is normal if you are using BOOST_THREAD_VERSION = 2, which is the default.

If you can not use BOOST_THREAD_VERSION = 2, use packaged_task<R> instead of packaged_task<R()>, but you couldn't work with non-nullary functions (you must then use boost::bind).

Which version are you using? Which compiler?

Last edited 9 years ago by viboes (previous) (diff)

comment:2 by anonymous, 9 years ago

I'm sorry, I thought I included the compiler information in the ticket.

Our build(s) use CMake 2.8.8, and gcc 4.6 (with some variance depending on system).

We are using BOOST_THREAD_VERSION = 4.

comment:3 by viboes, 9 years ago

I'm really sorry. This doesn't works yet for non C++98 compilers. Here it is the code

#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK
  #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
    template<typename R, typename ...ArgTypes>
    class packaged_task<R(ArgTypes...)>
    {
      typedef boost::shared_ptr<detail::task_base_shared_state<R(ArgTypes...)> > task_ptr;
      boost::shared_ptr<detail::task_base_shared_state<R(ArgTypes...)> > task;
  #else
    template<typename R>
    class packaged_task<R()>
    {
      typedef boost::shared_ptr<detail::task_base_shared_state<R()> > task_ptr;
      boost::shared_ptr<detail::task_base_shared_state<R()> > task;
  #endif

As you can see, only if BOOST_THREAD_PROVIDES_VARIADIC_THREAD you can use

boost::packaged_task<std::string(std::string&)>

I'm not sure Example 5 is a bug on Boost.Thread, I suspect that this is just not supported in C++03.

Unfortunately I have no time to develop this for C++03 compilers.

Last edited 9 years ago by viboes (previous) (diff)

comment:4 by viboes, 9 years ago

Anyway, I have tried to compile your example with C++11 and there are some issues. I will take a deeper look.

The line in example 6 seems suspect

            boost::thread task(boost::bind(&task_t::operator(), example));

Last edited 9 years ago by viboes (previous) (diff)

comment:5 by viboes, 9 years ago

This doesn't solves the issues,but I missed this code

svn diff future.hpp
Index: future.hpp
===================================================================
--- future.hpp	(revision 86540)
+++ future.hpp	(working copy)
@@ -2766,12 +2766,18 @@
             private:
               task_shared_state(task_shared_state&);
             public:
+#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
+                R (*f)(BOOST_THREAD_RV_REF(ArgTypes) ... );
+                task_shared_state(R (*f_)(BOOST_THREAD_RV_REF(ArgTypes) ... )):
+                    f(f_)
+                {}
+#else
                 R (*f)();
                 task_shared_state(R (*f_)()):
                     f(f_)
                 {}
+#endif
 
-
 #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
                 void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args)
                 {
@@ -2848,12 +2854,18 @@
             private:
               task_shared_state(task_shared_state&);
             public:
+#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
+                R& (*f)(BOOST_THREAD_RV_REF(ArgTypes) ... );
+                task_shared_state(R& (*f_)(BOOST_THREAD_RV_REF(ArgTypes) ... )):
+                    f(f_)
+                {}
+#else
                 R& (*f)();
                 task_shared_state(R& (*f_)()):
                     f(f_)
                 {}
+#endif
 
-
 #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
                 void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args)
                 {

Last edited 9 years ago by viboes (previous) (diff)

comment:6 by viboes, 9 years ago

Hi and sorry for the delay.

You need to use boost::ref() while passing by reference

            boost::thread task(boost::move(example), boost::ref(ans));

comment:7 by viboes, 9 years ago

Milestone: To Be Determined
Resolution: worksforme
Status: assignedclosed
Note: See TracTickets for help on using tickets.