Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

std::bind with member functions and C++20

813 views
Skip to first unread message

Bonita Montero

unread,
Apr 19, 2021, 5:23:34 AM4/19/21
to
I just tested std::bind with a member-function trick
and C++20 under MSVC:

#include <functional>
#include <utility>

template<typename T, typename RetType, typename ... Args>
auto obj_binder( T *this_, RetType (T::*fn)( Args ... ), Args &&...args )
{
using namespace std;
auto binderFn = []<typename T, typename RetType, typename ... Args>( T
* this_, RetType (T::*fn), Args &&...args ) -> RetType
{
return this_->*fn( forward<Args>( args ) ... );
};
return bind( binderFn, this_, fn, std::forward<Args>( args ) ... );
}

int main()
{
struct S
{
int a, b, c;
int sum( int d )
{
return a + b + c + d;
}
};
S s;
s.a = s.b = s.c = 1;
auto bound = obj_binder<S, int>( &s, &S::sum, 4 );
}

Unfortunately the compiler crashes with this.
C++20-support is still experimental with MSVC.

MrSpo...@xvdv0t9masednkplrcjyxfsl.tv

unread,
Apr 19, 2021, 5:32:30 AM4/19/21
to
On Mon, 19 Apr 2021 11:23:17 +0200
Bonita Montero <Bonita....@gmail.com> wrote:
>Unfortunately the compiler crashes with this.

My brain jusr crashed trying to understand what its supposed to do.


Bonita Montero

unread,
Apr 19, 2021, 7:05:13 AM4/19/21
to
>> Unfortunately the compiler crashes with this.

> My brain jusr crashed trying to understand what its supposed to do.

std::bind doesn't work with objects and member-functions.
So I wrote a obj_binder which you can supply an object
-pointer, a member-function within this object and the
parameters for this function. Later you can call this
generated object like bound().

Öö Tiib

unread,
Apr 22, 2021, 3:00:01 AM4/22/21
to
The boost::bind (that std::bind technically is) was specified before
lambdas for ease of constructing callable objects. It was very
useful more than decade ago.
After lambdas the bind is rarely of any use. Both products of
bind and lambda are callable objects of unspecified type but
lambdas are more flexible and easy to follow way to make
callable objects.
Can you explain why on your case that bind is worth using?

Bonita Montero

unread,
Apr 22, 2021, 4:07:16 AM4/22/21
to
> After lambdas the bind is rarely of any use. ...

I use bind very often to pack callables with their parameters
into a function-object, f.e. to execute it in another thread.
That's much more convenient than to define a structure which
is handed to a function in another thread.
And lambdas are extremely useful. I use them very often to
have functions in functions which wouldn't have any meaning
outside that function and to prevent repetitive code within
a function.
And I've got some helper-functions like this:

template<typename Function>
inline
typename std::invoke_result<Function>::type exc_default( Function &func,
std::exception_ptr *excPtr = nullptr )
{
using namespace std;
try
{
if( excPtr )
*excPtr = nullptr;
return func();
}
catch( ... )
{
if( excPtr )
*excPtr = current_exception();
return typename std::invoke_result<Function>::type();
}
}

This returns the default-value of a function if the function gives
an exception. Optionally the exception_ptr is saved (if not this is
optimized away. I use this like this:

wstring dstPath = copyNode->dstDir + L"\\" + extractFileName(
fleSrcDir.path.c_str() );
vfle_t dstFilesAndDirs = exc_default( [&]() { return fileList(
dstPath.c_str(), true, true ); }, &fileListExc );

So you see a lambda above inside exc_default.

Melzzzzz

unread,
Apr 22, 2021, 4:14:32 AM4/22/21
to
I stopped using exceptions couple of years ago...

--
current job title: senior software engineer
skills: x86 aasembler,c++,c,rust,go,nim,haskell...

press any key to continue or any other to quit...

Chris M. Thomasson

unread,
Apr 22, 2021, 4:20:25 AM4/22/21
to
Have you ever used scopeguard?

Iirc, one time I used an exception to rollback an operation... It was
called valid, but weird and dangerous back in an old Intel thread forum.
Iirc, it was for a raii guard on my read/write mutex. It would be fun to
try to find the post. Iirc it was somewhere in the following thread:

https://community.intel.com/t5/Intel-oneAPI-Threading-Building/Starvation-free-bounded-time-rw-mutex-with-wait-free-fast-pathed/td-p/895233

Bonita Montero

unread,
Apr 22, 2021, 5:32:59 AM4/22/21
to
> I stopped using exceptions couple of years ago...

That's stupid. Exceptions are very useful and you can't circumvent
them in C++ if you don't drop using the standard libary.

Andrey Tarasevich

unread,
Apr 22, 2021, 10:12:01 AM4/22/21
to
None of this has any relation to "C++20 support with MSVC" since the
code is obviously ill-formed. Reusing template parameter names inside a
template definition is prohibited in all versions of C++ language.

On top of that, the code is doing something nonsensical on top of
something even more nonsensical. I wanted to call it a "solution looking
for a problem", but I can't do even that since it makes no sense whatsoever.

> I just tested std::bind with a member-function trick

There's no such thing as "member-function trick" and there's no need for
any. `std::bind` works with member functions directly.

--
Best regards,
Andrey Tarasevich

Andrey Tarasevich

unread,
Apr 22, 2021, 10:12:54 AM4/22/21
to
On 4/19/2021 4:04 AM, Bonita Montero wrote:
>
> std::bind doesn't work with objects and member-functions.

Huh?

int main()
{
struct S
{
int a, b, c;
int sum( int d )
{
return a + b + c + d;
}
};
S s;
s.a = s.b = s.c = 1;

auto bound = std::bind(&S::sum, &s, 4);
return bound();

Bonita Montero

unread,
Apr 22, 2021, 11:51:13 AM4/22/21
to
> Huh?
>
>  int main()
>  {
>      struct S
>      {
>          int a, b, c;
>          int sum( int d )
>          {
>              return a + b + c + d;
>          }
>      };
>      S s;
>      s.a = s.b = s.c = 1;
>
>      auto bound = std::bind(&S::sum, &s, 4);
>      return bound();
>  }

Coooooool, I didn't know that this works.
YOU'RE MY HERO !

MrSpo...@i9d.com

unread,
Apr 22, 2021, 12:25:33 PM4/22/21
to
I must be missing the point. When would this ever be used?

Bonita Montero

unread,
Apr 22, 2021, 1:02:47 PM4/22/21
to
> I must be missing the point. When would this ever be used?

I have some code that passes shared pointers to structures which
include function-objects which were passed bind-objects on creation.
Currently I use global functions. But if these functions were member
-functions I could use this bind-variant.

Cholo Lennon

unread,
Apr 22, 2021, 1:17:04 PM4/22/21
to
Perhaps it's old fashioned, but a common use case for this it's a
callback event style similar to C# delegates. Instead of using virtual
functions, your class has several "delegates" modeled by std::function.
A user of your class can connect his/her callbacks to your delegates
using for that std::bind, which can accept any kind of callable object
(free functions, functors, member functions, lambdas, etc) with the
optional plus of binding/adding extra predefined values to your callback.

--
Cholo Lennon
Bs.As.
ARG

Bonita Montero

unread,
Apr 22, 2021, 1:25:24 PM4/22/21
to
Or more generally: function( bind() 9-objects can be used every time
you have a function-pointer which is passed some parameters and you
store both for later use.

Andrey Tarasevich

unread,
Apr 22, 2021, 1:35:44 PM4/22/21
to
I'm not sure what the focal point of your question is. What is that
"this" you are asking about?

`std::bind` functionality in general? Applying `std::bind` to member
functions specifically? Something else?

MrSpook...@_nb0l03nl53p.tv

unread,
Apr 23, 2021, 5:09:17 AM4/23/21
to
Ugh. Obfuscated code for the sake of being clever.

Cholo Lennon

unread,
Apr 23, 2021, 2:06:07 PM4/23/21
to
Why obfuscated? why "clever"? on the contrary, this way of using events
and callback is very common. Also, it's very simple and more flexible
than callbacks based on virtual functions, here is a small contrived
example:


#include <functional>
#include <iostream>
#include <string>


class Foo {
public:
using event_type = std::function<
void(Foo&, const std::string& some_event_data)>;

event_type onStart;
event_type onStop;


void start() {
if (onStart) onStart(*this, "start event data");

// ...
}

void stop() {
if (onStop) onStop(*this, "stop event data");

// ...
}
};


////////////////////////////////////////////////////
class EventHandler {
Foo foo_;

public:
EventHandler() {
using namespace std::placeholders;

foo_.onStart = std::bind(&EventHandler::onStart, this, _1, _2);
foo_.onStop = std::bind(&EventHandler::onStop, this, _1, _2);

foo_.start();
}

~EventHandler() {
foo_.stop();
}

void onStart(Foo&, const std::string& data) {
std::cout << "on start: " << data << '\n';
}

void onStop(Foo&, const std::string& data) {
std::cout << "on start: " << data << '\n';
}
};


////////////////////////////////////////////////////
void onMyStart(Foo&, const std::string& data) {
std::cout << "on start: " << data << '\n';
}

void onMyStop(Foo&, const std::string& data) {
std::cout << "on stot: " << data << '\n';
}


////////////////////////////////////////////////////
int main() {
// Example 1 with free function callbacks
Foo foo;

foo.onStart = onMyStart;
foo.onStop = onMyStop;

foo.start();
foo.stop();

// Example 2 with member function callbacks
EventHandler handler;

Cholo Lennon

unread,
Apr 23, 2021, 2:47:47 PM4/23/21
to
Fixed event messages:
std::cout << "on stop: " << data << '\n';
}
};


////////////////////////////////////////////////////
void onMyStart(Foo&, const std::string& data) {
std::cout << "on start: " << data << '\n';
}

void onMyStop(Foo&, const std::string& data) {
std::cout << "on stop: " << data << '\n';

MrSpook_...@pdj82ouz7mi_c.gov.uk

unread,
Apr 25, 2021, 11:18:46 AM4/25/21
to
On Fri, 23 Apr 2021 15:05:48 -0300
Cholo Lennon <cholo...@hotmail.com> wrote:
>Why obfuscated? why "clever"? on the contrary, this way of using events
>and callback is very common. Also, it's very simple and more flexible
>than callbacks based on virtual functions, here is a small contrived
>example:

I'm confused why you think the 2nd example is clearer or neater, requiring
as it does a 2nd class instead of handling everything in 1. But everyone has a
prefered style I suppose, its just a matter of taste.

Öö Tiib

unread,
Apr 25, 2021, 1:07:43 PM4/25/21
to
Yes some like to have certain structure of their programs where different
responsibilities are split between classes. Others like to have long blobs of
unstructured code vomits (kind of BASIC-programs) and classes are
inconvenience for them. They are usually embittered and confused why
so few people like their exquisite brand of "taste".

MrSpoo...@0kd0c4bkwzno.biz

unread,
Apr 26, 2021, 3:40:38 AM4/26/21
to
And others are too stupid to see how the 1st example could have been tidied
up to be a 1 line initialisation. But I'll leave that for you to figure out
genius.

Cholo Lennon

unread,
Apr 26, 2021, 8:35:24 PM4/26/21
to
I am just showing different use cases, I am not saying than the 1st
example is better than the 2nd one (or vice versa), but the latter is
very common, for example, in GUI applications... your Window/Dialog
class handles the events from the contained widgets. You can use free
functions as event handlers, but member functions has the context of the
parent class (of course, std::bind is very powerful so you can add the
context to your free functions if you want), i.e:


class MyWindow: public Window {
Button okCancel;
EditBox name;
EditBox address;

SomeWindowContext context;

void onClick(Button& button) {
if (button.isCancel()) {
...
}
else {
...
}
}

void onFocus(EditBox& editBox) {
// Use window's context here
}

void onLostFocus(EditBox& editBox) {
// Use window's context here
}

void initWidgets() {
...
okCancel.onClick = std::bind(&MyWindows::onClick, this, _1);

// For simplicity, callbacks are reused for similar widgets
name.onFocus = std::bind(&MyWindows::onFocus, this, _1);
name.onLostFocus = std::bind(&MyWindows::onLostFocus, this, _1);

address.onFocus = std::bind(&MyWindows::onFocus, this, _1);
address.onLostFocus = std::bind(&MyWindows::onLostFocus, this, _1);
...
}

public:
MyWindow(...): ... {
initWidgets();
}

void show() {
...
}

};


C# uses the same scheme via delegates (the .Net std::function
counterpart). Java used to have a similar approach in Swing, but
anonymous classes were used to redirect a widget event to the parent
class callback. In modern C++ we can use a lambda to code the event or
to redirect it to the parent class. There are a lot of approaches, all
of them with pros and cons.

Usually, the initWidget member function (initializeComponent/jbInit in
C#/Java) are managed by the GUI editor/IDE, so the event connection (as
well as the widget configuration) is automatic. In the old days of MFC,
a message map built with macros was the initWidget equivalence. The map
was managed by the Class Wizard (*) tool.

I use the past tense to talk about MFC because my last contact with it
was 16 years ago :-O but I think Class Wizard (and the message map)
still exist.

Bonita Montero

unread,
Apr 26, 2021, 11:33:02 PM4/26/21
to
>        // For simplicity, callbacks are reused for similar widgets
>        name.onFocus = std::bind(&MyWindows::onFocus, this, _1);
>        name.onLostFocus = std::bind(&MyWindows::onLostFocus, this, _1);
>        address.onFocus = std::bind(&MyWindows::onFocus, this, _1);
>        address.onLostFocus = std::bind(&MyWindows::onLostFocus, this, _1);

You would never use bind()-objects themselfes as callback-types because
the types are variable depending on the parameters. Usually you would
encapsulate them into a function-object which gives you the advantage,
that you can have any types of paramters with them, f.e.:
name.onFocus = function<void(param_type)>( bind(
&MyWindows::onFocus, this, _1 ) );

Cholo Lennon

unread,
Apr 26, 2021, 11:46:16 PM4/26/21
to
But for my previous post it should be clear that onFocus/onLostFocus/etc
are declared as std::function. For the sake of simplicity I didn't add
the declaration/definition of these properties (because they belong to
classes, Button and Editbox, whose code I didn't show)

MrSpook_1...@f5mda.co.uk

unread,
Apr 27, 2021, 3:37:52 AM4/27/21
to
On Mon, 26 Apr 2021 21:35:13 -0300
Cholo Lennon <cholo...@hotmail.com> wrote:
>On 4/25/21 12:18 PM, MrSpook_Xh_gU9dm@pdj82ouz7mi_c.gov.uk wrote:
>> On Fri, 23 Apr 2021 15:05:48 -0300
>> Cholo Lennon <cholo...@hotmail.com> wrote:
>>> Why obfuscated? why "clever"? on the contrary, this way of using events
>>> and callback is very common. Also, it's very simple and more flexible
>>> than callbacks based on virtual functions, here is a small contrived
>>> example:
>>
>> I'm confused why you think the 2nd example is clearer or neater, requiring
>> as it does a 2nd class instead of handling everything in 1. But everyone has
>a
>> prefered style I suppose, its just a matter of taste.
>>
>
>I am just showing different use cases, I am not saying than the 1st
>example is better than the 2nd one (or vice versa), but the latter is
>very common, for example, in GUI applications... your Window/Dialog
>class handles the events from the contained widgets. You can use free
>functions as event handlers, but member functions has the context of the
>parent class (of course, std::bind is very powerful so you can add the
>context to your free functions if you want), i.e:

Perhaps I'm just biased, but IMO if the answer is using std::bind() to link
an object method to a function pointer then you're asking the wrong
question. In simple code I'm sure it wouldn't be an issue, but in a complex
project that may be hacked about by dozens of people over the years the chances
the object may be deleted leaving a dangling function pointer elsewhere in
the code grows much higher.

>Usually, the initWidget member function (initializeComponent/jbInit in
>C#/Java) are managed by the GUI editor/IDE, so the event connection (as
>well as the widget configuration) is automatic. In the old days of MFC,
>a message map built with macros was the initWidget equivalence. The map
>was managed by the Class Wizard (*) tool.

A much safer and simpler method on an event is simply to call a callback
with the widget id. Event driven GUI code isn't speed critical so if safety
and simplicity costs a few extra cpu cycles then its a trade worth making.


0 new messages