4

I'm trying to mimic std::thread constructor functionality:

template< class Function, class... Args > 
explicit thread( Function&& f, Args&&... args );

I've tried stepping with debugger to see how it works but I couldn't figure it out.

How can I create and store bind type like thread's constructor does ?

Something like this (the syntax maybe wrong):

class myClass{
private:
auto bindType;

public:
template< class Function, class... Args > 
explicit myClass( Function&& f, Args&&... args ) : bindType(somehowBind(f, args) {}
void evaluate() {bindType();}
};

Example of usage:

int test(int i) {return i;}

int main(){
myClass my(test, 5);
my.evaluate();
}

Note that I don't care if somehowBind function will ignore the return type i.e. its return type can be something like std::function. All I wan't to do is understand how I can bind class... Args to a given function f such that after calling somehowBind it will act like std::bind does. To clarify my point you can think about what I'm trying to achieve as follow:

thread t(test, 5); // unlike the usual std:::thread, this one is created in suspended mode therefore I need somehow to bind `f` with `5` and store it
t.start(); // now t is executed

It's kinda reminds C# and Java threads, they not executed right after construction.

JobNick
  • 473
  • 1
  • 6
  • 18
  • 1
    I think you need to explain a little bit more what exactly you want to achieve. – tumdum Jan 25 '14 at 10:28
  • Somewhere deep down the layers of the wrapping code there will be an `std::tuple` storing the variadic arguments, or pointers, or references to them. As Tomasz said, give some more details on what your wrapping code should be like. – bobah Jan 25 '14 at 11:13
  • Are you looking for `std::function`? `class myClass { std::function m; public: template myClass(F&& f, Args&&... args) : m(std::bind(std::forward(f), std::forward(args)...)) {} void evaluate() {m();} };` – dyp Jan 25 '14 at 14:02
  • @dyp Yes that the one I was looking for, I didn't know that you can use such a syntax with std::bind (to forward ... to bind). I don't know why but in std::thread they complicated it too much. – JobNick Jan 25 '14 at 14:39
  • @dyp The return value of the resulting `std::bind` expression functor may not be `void`. – Felix Glas Jan 25 '14 at 14:39
  • @Snps But it is convertible to `void`. – dyp Jan 25 '14 at 14:57
  • @Snps Where does it say that you can't bind a function returning `void`? – dyp Jan 25 '14 at 15:02
  • @dyp Hmm interesting, although the why is not entirely clear to me. Does a `std::function` with a template parameter return type: `void` take any callable regardless of return type? – Felix Glas Jan 25 '14 at 15:27

1 Answers1

5

For starters, to bind some parameters to a function using std::bind you simpy do:

// Some function.
void printValues(int x, double y) {
    std::cout << x << " " << y << std::endl;
}

auto func = std::bind(printValues, 5, 2.0); // Bind params and return functor.
func(); // Evaluate function call (returns void in this case).

Next, to store a functor and its parameters in a class and you don't care about the return value when evaluating then simply use a lambda expression to wrap the std::bind expression (the lambda is used to drop the return value):

struct Foo {
    template <typename Function, typename... Args>
    Foo(Function&& func, Args&&... args) {
        auto f = std::bind(std::forward<Function>(func), std::forward<Args>(args)...);
        func_ = [f] { f(); };
        // func_ = [f{std::move(f)}] { f(); }; // In C++14 you can move capture.
    }
    void evaluate() { func_(); }
    std::function<void()> func_;
};

Also see this live example

If you're looking to store a variadic pack then see this answer: How to store variadic template arguments?

Community
  • 1
  • 1
Felix Glas
  • 15,065
  • 7
  • 53
  • 82
  • 1
    As said in my comment to the OP, the return value of the `bind` functor is convertible to void. You don't need to wrap it in a lambda. [Live example](http://coliru.stacked-crooked.com/a/65fe57cef319a026) – dyp Jan 25 '14 at 14:59
  • @dyp But I thought that the return value of the `bind` functor was that of the callable passed as an argument to it? E.g. `int` is not implicitly convertible to `void`? I'm just trying to get this. – Felix Glas Jan 25 '14 at 15:39
  • Hmm now it gets interesting. It seems as types are not implicitly, but only explicitly convertible to `void`. The requirements of `std::function` seem to require *implicit* conversion via *`INVOKE`*, but `std::function::operator()` includes a special case for `void` return types. libstdc++'s `std::function` implementation contains a special case to check if the passed entity is callable, namely it accepts any return type of the callable if the target return type is `void`. I.e. either that's a bug in the Standard (can easily be fixed) or a libstdc++ extension. – dyp Jan 25 '14 at 15:57
  • There has been a special exception for `void` in the drafts for C++11, but it has been removed, see [LWG 870](http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#870) I don't quite understand why it has been removed, though. – dyp Jan 25 '14 at 16:01
  • 1
    Seems you're right, this has been deliberately changed to allow supporting overload resolution disambiguation via SFINAE. See http://stackoverflow.com/a/9343400/420683 – dyp Jan 25 '14 at 16:08
  • 1
    @dyp Interesting indeed. I found the same post in tandem. Apparently your code will fail to compile on libc++, however it does work on libstdc++. – Felix Glas Jan 25 '14 at 16:11
  • This is really interesting, it does compiles for me using g++ 4.7.1. Maybe this is the reason std::thread's constructor implementation for capturing std::bind functor is more complicated. – JobNick Jan 25 '14 at 19:26