std::bind a bound function
std::bind
expressions, like their boost::bind
predecessors, support a type of composition operation. Your expression for w
is roughly equivalent to
auto w=std::bind(some_fun, std::bind(&foo::bar<int>, x, std::placeholders::_1) );
Nesting binds in this manner is interpreted as
- Calculate the value of
x.bar<int>(y)
wherey
is the first parameter passed into the resulting functor. - Pass that result into
some_fun
.
But x.bar<int>(y)
returns void, not any function type. That's why this doesn't compile.
As K-ballo points out, with boost::bind
, you can fix this problem with boost::protect
. As Kerrek SB and ildjarn point out, one way around this issue is: don't use auto
for f
. You don't want f
to have the type of a bind expression. If f
has some other type, then std::bind
won't attempt to apply the function composition rules. You might, for instance, give f
the type std::function<void(int)>
:
std::function<void(int)> f = std::bind(&foo::bar<int>, x, std::placeholders::_1);
auto w = std::bind(some_fun, f);
Since f
doesn't literally have the type of a bind expression, std::is_bind_expression<>::value
will be false on f
's type, and so the std::bind
expression in the second line will just pass the value on verbatim, rather than attempting to apply the function composition rules.
A problem that using std::bind to bind a function
Lvalue cannot be bound to rvalue reference.
When you have:
void bar(int&&) {}
int i = 0;
bar(i); // error
the last line will not compile.
This is the reason your code fails in second case.
std::bind
takes all passed arguments and copies/moves them into data member of newly generated functor:
std::bind(func,arg1,arg2)
gives you:
class closure1 {
Arg1 arg1;
Arg2 arg2;
void operator()() {
func(arg1,arg2);
}
};
and it provides also function call operator in which, arg(s)
are passed by value as Lvalues (4th dot in Member function operator() section of std::bind
reference:
Otherwise, the ordinary stored argument arg is passed to the invokable
object as lvalue argument: the argument vn in the std::invoke call
above is simply arg and the corresponding type Vn is T cv &, where cv
is the same cv-qualification as that of g.
So this:
auto f = std::bind(func, 1, "100", std::forward<F>(f2));
generates
class closure2 {
int i = 1;
std::string s = "100";
std::forward<void(int)> f;
void operator()() {
func(i,s,f); // [1]
}
};
and in [1] is problem, because f
as lvalue cannot be bound to rvalue reference declared in:
void func(int n, std::string s, std::function<void(int)> &&subf)
you can add another overload taking lvalue reference:
void func2(int n, std::string s, std::function<void(int)> &subf)
and call bind
with that version of your overloads.
There is no problem with bind_front_handler
because in this implementation all data members of generated functor are forwarded to a target:
func(...,std::forward< std::function<void()> >(f));
so f
will be casted into rvalue reference, and func
can accept this argument.
Demo
std::bind - vector as an argument in bound function
It really depends on what you want to do with the bound functions.
If they are going to be copied passed around (beyond the life of vv
), this is correct (and is going to copy vv
).
auto f1 = std::bind(&foo, vv); // 1)
This is also correct, (vv
is not going to be copied initially at least.)
auto f2 = std::bind(&foo, std::move(vv)); // 2)
but you will not have access to vv
after that point.
This is however the most likely scenario that I can deduce from your example:
if the bound function will be used locally while vv
is still alive it is more likely from the example that want you want f3
to hold a "reference" to vv
. This is done with the ref
convention:
auto f3 = std::bind(&foo, std::ref(vv));
how to pass a std::bind object to a function
You are using the wrong placeholders
, you need _1
:
auto fun = std::bind(&keyFormatter, sKeyFormat, std::placeholders::_1);
The number of the placeholder is not here to match the position of the args, but rather to choose which arguments to send to the original function in which position:
void f (int, int);
auto f1 = std::bind(&f, 1, std::placeholders::_1);
f1(2); // call f(1, 2);
auto f2 = std::bind(&f, std::placeholders::_2, std::placeholders::_1);
f2(3, 4); // call f(4, 3);
auto f3 = std::bind(&f, std::placeholders::_2, 4);
f3(2, 5); // call f(5, 4);
See std::bind
, especially the examples at the end.
How std::bind works with member functions
When you say "the first argument is a reference" you surely meant to say "the first argument is a pointer": the &
operator takes the address of an object, yielding a pointer.
Before answering this question, let's briefly step back and look at your first use of std::bind()
when you use
std::bind(my_divide, 2, 2)
you provide a function. When a function is passed anywhere it decays into a pointer. The above expression is equivalent to this one, explicitly taking the address
std::bind(&my_divide, 2, 2)
The first argument to std::bind()
is an object identifying how to call a function. In the above case it is a pointer to function with type double(*)(double, double)
. Any other callable object with a suitable function call operator would do, too.
Since member functions are quite common, std::bind()
provides support for dealing with pointer to member functions. When you use &print_sum
you just get a pointer to a member function, i.e., an entity of type void (Foo::*)(int, int)
. While function names implicitly decay to pointers to functions, i.e., the &
can be omitted, the same is not true for member functions (or data members, for that matter): to get a pointer to a member function it is necessary to use the &
.
Note that a pointer to member is specific to a class
but it can be used with any object that class. That is, it is independent of any particular object. C++ doesn't have a direct way to get a member function directly bound to an object (I think in C# you can obtain functions directly bound to an object by using an object with an applied member name; however, it is 10+ years since I last programmed a bit of C#).
Internally, std::bind()
detects that a pointer to a member function is passed and most likely turns it into a callable objects, e.g., by use std::mem_fn()
with its first argument. Since a non-static
member function needs an object, the first argument to the resolution callable object is either a reference or a [smart] pointer to an object of the appropriate class.
To use a pointer to member function an object is needed. When using a pointer to member with std::bind()
the second argument to std::bind()
correspondingly needs to specify when the object is coming from. In your example
std::bind(&Foo::print_sum, &foo, 95, _1)
the resulting callable object uses &foo
, i.e., a pointer to foo
(of type Foo*
) as the object. std::bind()
is smart enough to use anything which looks like a pointer, anything convertible to a reference of the appropriate type (like std::reference_wrapper<Foo>
), or a [copy] of an object as the object when the first argument is a pointer to member.
I suspect, you have never seen a pointer to member - otherwise it would be quite clear. Here is a simple example:
#include <iostream>
struct Foo {
int value;
void f() { std::cout << "f(" << this->value << ")\n"; }
void g() { std::cout << "g(" << this->value << ")\n"; }
};
void apply(Foo* foo1, Foo* foo2, void (Foo::*fun)()) {
(foo1->*fun)(); // call fun on the object foo1
(foo2->*fun)(); // call fun on the object foo2
}
int main() {
Foo foo1{1};
Foo foo2{2};
apply(&foo1, &foo2, &Foo::f);
apply(&foo1, &foo2, &Foo::g);
}
The function apply()
simply gets two pointers to Foo
objects and a pointer to a member function. It calls the member function pointed to with each of the objects. This funny ->*
operator is applying a pointer to a member to a pointer to an object. There is also a .*
operator which applies a pointer to a member to an object (or, as they behave just like objects, a reference to an object). Since a pointer to a member function needs an object, it is necessary to use this operator which asks for an object. Internally, std::bind()
arranges the same to happen.
When apply()
is called with the two pointers and &Foo::f
it behaves exactly the same as if the member f()
would be called on the respective objects. Likewise when calling apply()
with the two pointers and &Foo::g
it behaves exactly the same as if the member g()
would be called on the respective objects (the semantic behavior is the same but the compiler is likely to have a much harder time inlining functions and typically fails doing so when pointers to members are involved).
Is it possible to access the arguments from an std::bind object?
std::bind(&EditorWidget::editRow, editorWidget, item)
std::bind
here is creating a functional object that takes a pointer to a member function EditorWidget::editRow
, bound to an object editorWidget
, using the parameter item
. What you've done is actually fix the parameter to the function EditorWidget::editRow
with the parameter item
. So effectively you've created a function object that takes no argument (since you've fixed it), and returns void
.
There's actually no need for the constructor of PopupMenu
to have a second parameter of type RowItem*
. You could change the constructor like so:
PopupMenu::PopupMenu(std::function<void()> editRowFunction)
: _editRowFunction(editRowFunction)
{
}
and then call your function object like this:
PopupMenu::execute(} {
_editRowFunction();
}
In your current code the parameter _item
is not being used by the function object you pass into the constructor PopupMenu
. It satisfies the compiler since _editRowFunction
is of type std::function<void(RowItem*)>
.
Here's a simple example to illustrate to the point:
#include <iostream>
#include <functional>
struct callable
{
callable(std::function<void(std::string)> fn) : mFn(fn)
{}
std::function<void(std::string)> mFn;
void Run() { mFn("world"); }
};
struct Foo {
void print(std::string msg)
{
std::cout << msg << '\n';
}
};
int main()
{
Foo f;
auto fn = std::bind(&Foo::print, &f, "hello");
fn();
callable c(fn);
c.Run(); //expecting "world" to be printed
}
You might expect the output to be:
hello
world
but actually it's:
hello
hello
Live demo.
What I could do is change the definition of the function object like this:
auto fn = std::bind(&Foo::print, &f, std::placeholders::_1); //uses a placeholder
and I get the expected output. You could do something similar without having to make many changes to your current implementation.
Related Topics
Ctrl + C Interrupt Event Handling in Linux
Why Don't the C or C++ Standards Explicitly Define Char as Signed or Unsigned
Is It Reasonable to Use Std::Basic_String<T> as a Contiguous Buffer When Targeting C++03
Exit() Call Inside a Function Which Should Return a Reference
How to Append an Int to a String in C++
Create New C++ Object at Specific Memory Address
C++ Std::Vector VS Array in the Real World
What Is an In-Place Constructor in C++
Const Correctness for Value Parameters
C++ Object Size with Virtual Methods
How to Use String.Substr() Function
Why Doesn't My Template Accept an Initializer List
Why Stdfax.H Should Be the First Include on Mfc Applications
C++ HTML Template Framework, Templatizing Library, HTML Generator Library
Fast N Choose K Mod P for Large N