3

The IDE complains to me that thread does not contain the number of parameters that I am passing it. This is because there are too many of them, I believe...

I had this same issue when I was using the standard library for threads, but do to compatibility issues, I need to use the Boost::threads. HERE is the link to my previous question where someone explained that the issue was caused by veriadic templates.

This was indeed the issue, however, after switching to boost threads, that error comes back and changing the veriadic max does not fix it.

this is my thread declaration

boost::thread db(writeToDB, coordString, time, std::to_string(id), imageName, azimuth, att_pitch, att_roll, yaw, cam_pitch, cam_roll);

EDIT:

Here is how I tried the bind function:

boost::thread db(boost::bind(::writeToDB, coordString, time, std::to_string(id), imageName, azimuth, att_pitch, att_roll, yaw, cam_pitch, cam_roll));

And the current IDE is Visual Studio 2013, however it needs to be compatible with Visual Studio 2008

Also here is the actual error I am recieveing:

ERROR:

Error 6 error C2661: 'boost::thread::thread' : no overloaded function takes 11 arguments c:\users\hewittjc\desktop\final project\project1\clientexample.cpp 174 1 Project1

9
  • A simple google search gave the answer - Repeat of stackoverflow.com/questions/5730747/…
    – Rajeshwar
    Commented Dec 9, 2014 at 20:22
  • I have tried the bind function, it give the same error as thread Commented Dec 9, 2014 at 20:26
  • Please show us how you used the bind method with the thread constructor ?
    – Rajeshwar
    Commented Dec 9, 2014 at 20:29
  • What is The IDE? What is the actual error? Commented Dec 9, 2014 at 20:31
  • I have answered the above in an edit. Thanks for the interest! Commented Dec 9, 2014 at 20:33

3 Answers 3

2

Boost.Thread (that internally exploits Boost.Bind for binding arguments) supports only some fixed number of arguments (doc):

Thread Constructor with arguments

template <class F,class A1,class A2,...>
thread(F f,A1 a1,A2 a2,...);

Preconditions:

F and each An must be copyable or movable.

Effects:

As if thread(boost::bind(f,a1,a2,...)). Consequently, f and each an are copied into internal storage for access by the new thread.

Postconditions:

*this refers to the newly created thread of execution.

Throws:

boost::thread_resource_error if an error occurs.

Error Conditions:

resource_unavailable_try_again : the system lacked the necessary resources to create an- other thread, or the system-imposed limit on the number of threads in a process would be exceeded.

Note:

Currently up to nine additional arguments a1 to a9 can be specified in addition to the function f.

Clearly, this means that passing 11 arguments (as you do) must result in the error you see: "no overloaded function takes 11 arguments".

Unfortunately, there is no easy way of extending the limit. Possible solutions are:

  • reducing the overall number of arguments (you're only one ahead of the limit)

  • using other library for binding arguments like Boost.Phoenix

  • wrapping arguments in a class-type variable (or at least some of them)

  • switching to std::thread on a C++11 compiler that fully supports variadic templates.

1
  • Ended up pass a struct instead but yea I guess I should have seen that NOTE: there huh? Ha. Thank you! Commented Dec 10, 2014 at 19:16
0

From the Boost.Thread documentation:

Note:

Currently up to nine additional arguments a1 to a9 can be specified in addition to the function f.

Boost.Bind has the same limitation. You can try std::tr1::bind, which MSVC 2008 has, but I suspect it'll be similar there -- you really need variadic templates to make bind properly, and MSVC 2008 doesn't have them. I think the only guys actually crazy enough to see this through with preprocessor metaprogramming were the Boost.Spirit people, who made it into Boost.Phoenix. There you can specify an upper bound by preprocessor like so:

// Set this before headers are included.
// ...best set it projectwide. I don't know if funny stuff happens if Phoenix is
// used with different limits in different translation units.
//
// Also, please read the stuff below.
//
#define BOOST_PROTO_MAX_ARITY 20
#define BOOST_PROTO_MAX_LOGICAL_ARITY 20

#include <boost/phoenix/bind.hpp>
#include <boost/thread.hpp>

#include <iostream>

void foo(int x0, int x1, int x2, int x3, int x4,
         int x5, int x6, int x7, int x8, int x9,
         int x10)
{
  std::cout << x0 << x1 << x2 << x3 << x4
            << x5 << x6 << x7 << x8 << x9
            << x10 << "\n";
}

int main() {
  boost::thread th(boost::phoenix::bind(&foo, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
  th.join();
}

Now, this feature is fairly rough. I get the feeling that the preprocessor macros controlling this have been treated as an afterthought. In the Boost.Phoenix docs, it says you should be able to control this through BOOST_PHOENIX_LIMIT, and that was true once upon a time, but during the creation of the Boost.Proto backbone, it appears to have changed and that the docs were not updated. It's also rough around the edges in other ways. For example, it only works for me with a value of 20 (and, I suspect, 30, 40, etc. if you're really patient) -- anything from 11 to 19 gives huge compiler errors -- and it takes ages to compile because it suddenly has 1048576 function template overloads to handle.

So this works (for me, with Boost 1.55.0), but it's not really something to rely on. Instead, I suggest you either group your arguments together in structs so you have less than 10 arguments to pass to writeDB, or you write your own functor (with blackjack and...nevermind) like

// "..." to mean the rest of the arguments
class writeDBFunctor {
public:
  writeDBFunctor(std::string coordString, ...) : coordString(cordString), ... { }

  void operator()() {
    writeDB(coordString, ...);
  }

private:
  std::string coordString;
  // ...and the other arguments saved here
}

and give that to the boost::thread.

0

Well you just have to create a temporary "box of things" if you wanna use boost thread. Simple example: I wanna boost::thread following...

/// d2dclass
static void draw_tree(ID2D1RenderTarget* d2rt,
                      ID2D1Brush*        brush,
                      float X, float Y, float len,
                      int level,
                      float angle = -DirectX::XM_PIDIV2,
                      float dispersion = DirectX::XM_PIDIV2,
                      int split = 2, float shrink = 0.5f,
                      float sw = 1.0f,
                      ID2D1StrokeStyle* ss = NULL,
                      HANDLE interrupt = NULL);

Its a simple recursive D2D1 tree drawing function.

Define a parameter data holder.

struct dth_para {
    ID2D1RenderTarget* _d2rt;
    ID2D1Brush*      _brush;
    float _X;
    float _Y;
    float _len;
    int _level;
    float _angle;
    float _dispersion;
    int _split;
    float _shrink;
    float _sw;
    ID2D1StrokeStyle* _ss;
    HANDLE _interrupt;
};

Define a simple thread call version with boost::thread& (reference) use a template. (you might wanna do several at the same time) and an impl version. Actually this part im not sure its needed. Each thread do create seperate workspace but it cant hurt. Declare a static varible in the first function so it doesnt disappear from stack.

/// class d2dclass

template<size_t num_tree>
static void draw_tree_thread(boost::thread& tth,
                             ID2D1RenderTarget* d2rt,
                             ID2D1Brush*         brush,
                             float X, float Y, float len,
                             int level,
                             float angle = -DirectX::XM_PIDIV2,
                             float dispersion = DirectX::XM_PIDIV2,
                             int split = 2, float shrink = 0.5f,
                             float sw = 1.0f,
                             ID2D1StrokeStyle* ss = NULL,
                             HANDLE interrupt = NULL) {
    static dth_para tree_para;
    tree_para._d2rt = d2rt;
    tree_para._brush = brush;
    tree_para._X = X;
    tree_para._Y = Y;
    tree_para._len = len;
    tree_para._level = level;
    tree_para._angle = angle;
    tree_para._dispersion = dispersion;
    tree_para._split = split;
    tree_para._shrink = shrink;
    tree_para._sw = sw;
    tree_para._ss = ss;
    tree_para._interrupt = interrupt;
    tth = boost::thread(boost::bind(&draw_tree_thread_mpl, boost::ref(tree_para)));
}

static void draw_tree_thread_mpl(dth_para& params) {
    draw_tree(params._d2rt,
              params._brush,
              params._X,
              params._Y,
              params._len,
              params._level,
              params._angle,
              params._dispersion,
              params._split,
              params._shrink,
              params._sw,
              params._ss,
              params._interrupt);
}

And the just call the appropiate function.

boost::thread sth;
d2dclass::draw_tree_thread<0>(sth,
                              d3d->getd2rendertarget(),
                              pRadialGradientBrush0,
                              d3d->get_ww() / 2,
                              d3d->get_wh() - TREE_LEN,
                              TREE_LEN,
                              LEVELS,
                              -DirectX::XM_PIDIV2,
                              DISPERSION,
                              2,
                              OPA_SHRINK,
                              -6.0f,
                              NULL,
                              interrupt);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.