1

I'm trying to create a object that can be given a function and its parameters to his constructor. This class will then call the given function inside a lambda that is instead passed to a thread. Something along the lines of

class worker {
public:
    template <class Fn, class... Args>
    explicit worker(Fn f, Args ... args) {
        t = std::thread([&]() -> void {
                f(args...);
        });
    }
private:
    std::thread t;
};

int main() {
    worker t([]() -> void {
        for (size_t i = 0; i < 100; i++)
            std::cout << i << std::endl;
    });

    return 0;
}

But I get the following error

error: parameter packs not expanded with '...': f(args...);

What am I doing wrong here? Any help would be appreciated.

aram
  • 1,415
  • 13
  • 27
  • 5
    What compiler? Unrelated to your compiler error, but you should be aware that the code as written is going to almost certainly result in undefined behavior, because the lambda captures by reference, is moved into a thread, then the scope where the data is valid is left. – Yakk - Adam Nevraumont Jul 27 '16 at 13:16
  • 3
    Looks like you have too many braces. – TartanLlama Jul 27 '16 at 13:17
  • 2
    Your code does not compile as it is, there brackets everywhere, `t` is not declared, ...After cleaning, I have no problem compiling this, so you should provide an [MCVE](http://stackoverflow.com/help/mcve). – Holt Jul 27 '16 at 13:18
  • @TartanLlama There was more stuff inside the lambda leftover brace after cleaning it up – aram Jul 27 '16 at 13:19
  • 1
    @Aram Add the compiler version to your question - This is clearly specific to gcc < 4.9 (it works with gcc 4.9). Upgrading your compiler would be the easiest way to fix this if you can. – Holt Jul 27 '16 at 13:24
  • @Aram for gcc4.8 you might use std::tuple to pass data to your wrapped function: `worker(Fn f, Args ... args) { std::tuple p(argc...); .... f(p) .....` – PiotrNycz Jul 27 '16 at 13:29
  • It compiles fine with GCC 4.9. Can you try a newer compiler? – Elvis Teixeira Jul 27 '16 at 13:43

1 Answers1

2

As said in the comments, this compile fine with gcc-4.9 (and above), but if you need to use gcc-4.8 you can add parameters to the lambda in the worker constructor and pass the arguments via the std::thread constructor:

class worker {
public:
    template <class Fn, class... Args>
    explicit worker(Fn f, Args ...args) {
        t = std::thread([f](Args ...largs) -> void {
                f(largs...);
        }, std::move(args)...);
    }
private:
    std::thread t;
};

This will also create copy of the arguments in the lambda arguments, unlike the capture by reference you were using [&] that was probably incorrect in this case (see @Yakk comment).

Holt
  • 36,600
  • 7
  • 92
  • 139