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

Creating lambdas in static factory function

71 views
Skip to first unread message

bitrex

unread,
Aug 18, 2018, 1:44:13 AM8/18/18
to
I have the following compiling under gcc 8.2, -std=c++11

#include <functional>
#include <iostream>

typedef int ContextType;

struct Foo {
Foo(std::function<int()>&& bar) : bar_(bar) {}

std::function<int()> bar_;

int getValue()
{
return bar_();
}
};

struct Baz {
template <int (*Ptr)(int)>
static Foo* create(const ContextType& ctx) {
std::function<int()> bar = [&]() { return Ptr(ctx); };
return new Foo(std::move(bar));
}
};

int A(int a)
{
return a;
}

First I try:

int main()
{
auto baz1 = Baz::create<&A>(1);
auto baz2 = Baz::create<&A>(2);
std::cout << baz1->getValue() << std::endl; //prints 2;
std::cout << baz2->getValue() << std::endl; //prints 2;
}

And then:

int main()
{
auto a = 1;
auto b = 2;
auto baz1 = Baz::create<&A>(a);
auto baz2 = Baz::create<&A>(b);
std::cout << baz1->getValue() << std::endl; //prints 1;
std::cout << baz2->getValue() << std::endl; //prints 2;
}

If I change static Foo* create(const ContextType& ctx) {
std::function<int()> bar = [&]() { return Ptr(ctx); };
return new Foo(std::move(bar));
}

to take a non-const reference I get a compiler warning about
non-convertibility in the first example. Where can I read in the
standard about how captures work in this situation?


Marcel Mueller

unread,
Aug 18, 2018, 3:27:19 AM8/18/18
to
Am 18.08.2018 um 07:43 schrieb bitrex:
> I have the following compiling under gcc 8.2, -std=c++11
[...]
> If I change static Foo* create(const ContextType& ctx) {
>     std::function<int()> bar = [&]() { return Ptr(ctx); };
>     return new Foo(std::move(bar));
>   }
>
> to take a non-const reference I get a compiler warning about
> non-convertibility in the first example. Where can I read in the
> standard about how captures work in this situation?

What did you change?

Your code works for me without any warning.


Marcel

Alf P. Steinbach

unread,
Aug 18, 2018, 3:57:31 AM8/18/18
to
On 18.08.2018 07:43, bitrex wrote:
> I have the following compiling under gcc 8.2, -std=c++11
>
> #include <functional>
> #include <iostream>
>
> typedef int ContextType;
>
> struct Foo {
>   Foo(std::function<int()>&& bar) : bar_(bar) {}
>
>   std::function<int()> bar_;
>
>   int getValue()
>   {
>       return bar_();
>   }
> };

Here `Foo` can only be constructed with a temporary (or rvalue reference
returned by function, more generally an rvalue expression) as argument.
That's IMO a needless restriction. Instead, do this, which accepts both
lvalue and rvalue argument without incurring more copy operations:

struct Foo {
Foo(std::function<int()> bar) : bar_(move(bar)) {}

std::function<int()> bar_;

int value() const
{
return bar_();
}
};


> struct Baz {
>   template <int (*Ptr)(int)>
>   static Foo* create(const ContextType& ctx) {
>     std::function<int()> bar = [&]() { return Ptr(ctx); };
>     return new Foo(std::move(bar));
>   }
> };

This can be simplified to

struct Baz {
template <int (*Ptr)(int)>
static Foo* create(const ContextType& ctx) {
auto bar = [&]() { return Ptr(ctx); };
return new Foo(std::move(bar));
}
};


> int A(int a)
> {
>     return a;
> }
>
> First I try:
>
> int main()
> {
>     auto baz1 = Baz::create<&A>(1);
>     auto baz2 = Baz::create<&A>(2);
>     std::cout << baz1->getValue() << std::endl; //prints 2;
>     std::cout << baz2->getValue() << std::endl; //prints 2;
> }

That outputs 1 2 for me, not 2 2. But it's not reliable. The temporary
`int`, a.k.a. `ContextType`, that each lambda refers to, has ceased to
formally exist when the output statements are executed, i.e. there's
formally Undefined Behavior due to Dangling References.


> And then:
>
> int main()
> {
>     auto a = 1;
>     auto b = 2;
>     auto baz1 = Baz::create<&A>(a);
>     auto baz2 = Baz::create<&A>(b);
>     std::cout << baz1->getValue() << std::endl; //prints 1;
>     std::cout << baz2->getValue() << std::endl; //prints 2;
> }

This one appears to be OK, no UB as far as I can see. :)


> If I change static Foo* create(const ContextType& ctx) {
>     std::function<int()> bar = [&]() { return Ptr(ctx); };
>     return new Foo(std::move(bar));
>   }
>
> to take a non-const reference I get a compiler warning about
> non-convertibility in the first example.

Yes, you can't bind an rvalue expression such as a numerical literal, to
a reference to non-const.

However, since g++ doesn't have a language extension that allows you to
do that you should get an outright error, not a warning.

Checking... Yep, you get an error with g++ (version 7.3). And also with
Visual C++ (2017).


> Where can I read in the
> standard about how captures work in this situation?

All you need to know is that capturing by reference gives you a lambda
object with a references to whatever's captured, instead of copies.


Cheers & hth.,

- Alf

Paavo Helde

unread,
Aug 18, 2018, 4:05:22 AM8/18/18
to
On 18.08.2018 8:43, bitrex wrote:
> I have the following compiling under gcc 8.2, -std=c++11
>
> #include <functional>
> #include <iostream>
>
> typedef int ContextType;
>
> struct Foo {
> Foo(std::function<int()>&& bar) : bar_(bar) {}
>
> std::function<int()> bar_;
>
> int getValue()
> {
> return bar_();
> }
> };
>
> struct Baz {
> template <int (*Ptr)(int)>
> static Foo* create(const ContextType& ctx) {
> std::function<int()> bar = [&]() { return Ptr(ctx); };
> return new Foo(std::move(bar));
> }
> };
>
> int A(int a)
> {
> return a;
> }
>
> First I try:
>
> int main()
> {
> auto baz1 = Baz::create<&A>(1);
> auto baz2 = Baz::create<&A>(2);
> std::cout << baz1->getValue() << std::endl; //prints 2;
> std::cout << baz2->getValue() << std::endl; //prints 2;
> }

Isn't this just an obscure way to create dangling references which has
actually nothing to do with lambdas? I think the relevant standard
clause is 12.2/5:

"A temporary object bound to a reference parameter in a function call
(5.2.2) persists until the completion of the full-expression containing
the call."

Here, I think this means that the temporary created from 1 persists
until the end of the line:

auto baz1 = Baz::create<&A>(1);

After that, the lambda is left with a dangling reference inside. Or is
there something else?




bitrex

unread,
Aug 18, 2018, 12:09:31 PM8/18/18
to
Great, got it now, thank you. Being able to store lambdas in objects and
construct varying kinds in templated factory methods is very nice
feature to have, particularly when interfacing with legacy code or C
APIs, how did I live without this feature before...

Richard

unread,
Aug 20, 2018, 12:08:21 PM8/20/18
to
[Please do not mail me a copy of your followup]

It looks like you're trying to do some sort of callback mechanism.

IMO, callbacks in C++ are best done without function pointers, lambdas
or std::function<>. Simply use an abstract interface that is consumed
by the notifier and implemented by the recipient. All the crazy
function pointer business disappears from your code, the abstract
reads clean and there isn't any worries about ABI either. This is one
reason why COM uses interfaces for callbacks (e.g. Connection Points).
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Scott Lurndal

unread,
Aug 20, 2018, 1:16:18 PM8/20/18
to
legaliz...@mail.xmission.com (Richard) writes:
>[Please do not mail me a copy of your followup]
>
>It looks like you're trying to do some sort of callback mechanism.
>
>IMO, callbacks in C++ are best done without function pointers, lambdas
>or std::function<>. Simply use an abstract interface that is consumed
>by the notifier and implemented by the recipient. All the crazy
>function pointer business disappears from your code, the abstract
>reads clean and there isn't any worries about ABI either. This is one
>reason why COM uses interfaces for callbacks (e.g. Connection Points).


Now here, I agree 100%. However, the 'No Multiple Inheritance' police may
object.

Manfred

unread,
Aug 20, 2018, 1:56:51 PM8/20/18
to
On 8/20/2018 7:16 PM, Scott Lurndal wrote:
> legaliz...@mail.xmission.com (Richard) writes:
>> [Please do not mail me a copy of your followup]
>>
>> It looks like you're trying to do some sort of callback mechanism.
>>
>> IMO, callbacks in C++ are best done without function pointers, lambdas
>> or std::function<>. Simply use an abstract interface that is consumed
>> by the notifier and implemented by the recipient. All the crazy
>> function pointer business disappears from your code, the abstract
>> reads clean and there isn't any worries about ABI either. This is one
>> reason why COM uses interfaces for callbacks (e.g. Connection Points).
I would not agree on this. Interface pointers are a replacement for
callback functions in COM because there is no such thing as a function
object (or pointer) in COM.
Function objects and pointers are IMO a powerful feature of C++ which,
as all power features, need to be known how to use properly.
They are essential in writing effective generic algorithms as one example.

>
>
> Now here, I agree 100%. However, the 'No Multiple Inheritance' police may
> object.
>
Well, pure abstract interfaces usually benefit from pardon by such
police (and BTW this is the rule in .NET).

Richard

unread,
Aug 20, 2018, 4:16:24 PM8/20/18
to
[Please do not mail me a copy of your followup]

Manfred <non...@add.invalid> spake the secret code
<plevcl$934$1...@gioia.aioe.org> thusly:

>I would not agree on this. Interface pointers are a replacement for
>callback functions in COM because there is no such thing as a function
>object (or pointer) in COM.

Actually COM doesn't care -- a function pointer is just a data type
and COM doesn't care about data types. It has a few well supported
data types that don't require custom marshalling to move across object
boundaries, but there is nothing preventing you from using COM method
calls that accept or return function pointers.

>Function objects and pointers are IMO a powerful feature of C++ which,
>as all power features, need to be known how to use properly.

The function pointer syntax is painful and there are some quirks in
the grammar as a result. It's been my experience that as soon as you
need one callback, you need a second one in short order. Then there's
the added annoyance that with function pointers you have to go through
hoops to get the 'this' pointer passed around properly and you end up
writing two methods on a C++ object for every callback method you
implement -- once for a static "C" style function pointer that
delegates to an instance method and the instance method. Unless
you're required to have a C style API, it's simply easier to make an
abstract interface that represents the contract for the interaction
between two objects. It's also easier to create mock objects for unit
testing if you follow this strategy.

>They are essential in writing effective generic algorithms as one example.

They are not essential for making generic algorithms. An abstract
polymorphic interface could just as easily have been used. A template
policy class could just as easily have been used. They just didn't use
it because the STL algorithms originate in a functional programming style.

Jorgen Grahn

unread,
Aug 20, 2018, 4:50:58 PM8/20/18
to
On Mon, 2018-08-20, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Manfred <non...@add.invalid> spake the secret code
> <plevcl$934$1...@gioia.aioe.org> thusly:
>
>>I would not agree on this. Interface pointers are a replacement for
>>callback functions in COM because there is no such thing as a function
>>object (or pointer) in COM.
>
> Actually COM doesn't care -- a function pointer is just a data type
> and COM doesn't care about data types. It has a few well supported
> data types that don't require custom marshalling to move across object
> boundaries, but there is nothing preventing you from using COM method
> calls that accept or return function pointers.
>
>>Function objects and pointers are IMO a powerful feature of C++ which,
>>as all power features, need to be known how to use properly.
>
> The function pointer syntax is painful and there are some quirks in
> the grammar as a result.

> It's been my experience that as soon as you need one callback, you
> need a second one in short order.

I don't agree with the rest of your argument, but with this. I think
people are sometimes so eager to use lambdas and std::function and
Boost signals, that instead of passing a pointer to some class Foo,
they pass the N functions of an implementation of Foo instead.

Passing more than one function at a time may be a code smell.

[snip]

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Scott Lurndal

unread,
Aug 20, 2018, 4:55:54 PM8/20/18
to
legaliz...@mail.xmission.com (Richard) writes:
>[Please do not mail me a copy of your followup]

>The function pointer syntax is painful and there are some quirks in
>the grammar as a result. It's been my experience that as soon as you
>need one callback, you need a second one in short order.

I've used them, on occasion. One becomes accustomed to the syntax.

if (branch || !p_fetch_fault) {
failed = (this->*opp->op_insn)(opp);
}

This was in an instruction decoder dispatch loop.

struct p_op {
const char *op_name; // Opcode name
unsigned char op_opcode; // 2-digit numeric opcode
unsigned char op_operands; // Operand count
unsigned char op_literal:1, // A field literal allowed
op_afindirect:1, // AF indirect allowed
op_bfindirect:1, // BF indirect allowed
op_flags:1, // COM/OVF flags modified
op_bfhex:1, // Treat BF field as hex
op_noafbf:1; // No AFBF field for instruction
bool (c_processor::*op_insn)(struct _op *);
};

struct c_processor::p_op c_processor::p_optable[] = {
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 1, &c_processor::op_nul }, // 00
{ "INC", OP_INC, 2, 1, 1, 1, 1, 0, 0, &c_processor::op_inc }, // 01
{ "ADD", OP_ADD, 3, 1, 1, 1, 1, 0, 0, &c_processor::op_add }, // 02
{ "DEC", OP_DEC, 2, 1, 1, 1, 1, 0, 0, &c_processor::op_dec }, // 03
{ "SUB", OP_SUB, 3, 1, 1, 1, 1, 0, 0, &c_processor::op_sub }, // 04
{ "MPY", OP_MPY, 3, 1, 1, 1, 1, 0, 0, &c_processor::op_mpy }, // 05
{ "DIV", OP_DIV, 3, 1, 1, 1, 1, 0, 0, &c_processor::op_div }, // 06
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 0, &c_processor::op_nul }, // 07
{ "MVD", OP_MVD, 3, 0, 1, 1, 0, 0, 0, &c_processor::op_mvd }, // 08
{ "MVL", OP_MVL, 3, 0, 1, 1, 0, 0, 0, &c_processor::op_mvl }, // 09
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 1, &c_processor::op_nul }, // 0a
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 1, &c_processor::op_nul }, // 0b
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 1, &c_processor::op_nul }, // 0c
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 1, &c_processor::op_nul }, // 0d
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 1, &c_processor::op_nul }, // 0e
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 1, &c_processor::op_nul }, // 0f

{ "MVA", OP_MVA, 2, 1, 1, 1, 1, 0, 0, &c_processor::op_mva }, // 10
{ "MVN", OP_MVN, 2, 1, 1, 1, 1, 0, 0, &c_processor::op_mvn }, // 11
{ "MVW", OP_MVW, 2, 0, 1, 1, 0, 0, 0, &c_processor::op_mvw }, // 12
{ "MVC", OP_MVC, 2, 0, 1, 1, 0, 0, 0, &c_processor::op_mvc }, // 13
{ "MVR", OP_MVR, 2, 1, 1, 1, 0, 0, 0, &c_processor::op_mvr }, // 14
{ "TRN", OP_TRN, 3, 0, 1 ,1 ,0, 0, 0, &c_processor::op_trn }, // 15
{ "SDE", OP_SDE, 2, 1, 1, 1, 1, 0, 0, &c_processor::op_sde }, // 16
{ "SDU", OP_SDU, 2, 1, 1, 1, 1, 0, 0, &c_processor::op_sde }, // 17
{ "SZE", OP_SZE, 2, 1, 1, 1, 1, 0, 0, &c_processor::op_sze }, // 18
{ "SZU", OP_SZU, 2, 1, 1, 1, 1, 0, 0, &c_processor::op_sze }, // 19
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 1, &c_processor::op_nul }, // 1a
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 1, &c_processor::op_nul }, // 1b
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 1, &c_processor::op_nul }, // 1c
{ "NUL", OP_nul, 0, 0, 0, 0, 0, 0, 1, &c_processor::op_nul }, // 1d

...

Thiago Adams

unread,
Aug 20, 2018, 5:04:04 PM8/20/18
to
On Monday, August 20, 2018 at 5:16:24 PM UTC-3, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Manfred spake the secret code
> <thusly:
>
> >I would not agree on this. Interface pointers are a replacement for
> >callback functions in COM because there is no such thing as a function
> >object (or pointer) in COM.
>
> Actually COM doesn't care -- a function pointer is just a data type
> and COM doesn't care about data types. It has a few well supported
> data types that don't require custom marshalling to move across object
> boundaries, but there is nothing preventing you from using COM method
> calls that accept or return function pointers.
>
> >Function objects and pointers are IMO a powerful feature of C++ which,
> >as all power features, need to be known how to use properly.
>
> The function pointer syntax is painful and there are some quirks in
> the grammar as a result. It's been my experience that as soon as you
> need one callback, you need a second one in short order. Then there's
> the added annoyance that with function pointers you have to go through
> hoops to get the 'this' pointer passed around properly and you end up
> writing two methods on a C++ object for every callback method you
> implement -- once for a static "C" style function pointer that
> delegates to an instance method and the instance method. Unless
> you're required to have a C style API, it's simply easier to make an
> abstract interface that represents the contract for the interaction
> between two objects. It's also easier to create mock objects for unit
> testing if you follow this strategy.
>

I miss lambdas in C. Even lambdas without capture would
be useful for me.

Generally I can represent everything I need using C basic
concepts like structs and functions.

But when I need lambdas the sparse representation
in C using structs and functions makes the code much harder
do read and maintain.

For instance

void Run(void (*callback)(void*), void* data);

void F()
{
Run([](void* data){

printf("first");
Run([](void* data){
printf("second");
}, 0);
}, 0);
}

Everything is inside F with small scopes.
In case I remove F everything is removed as it should be.


Comparing with sparse C solution:


void Run(void (*callback)(void*), void* data);

static void _lambda_1(void* data){
printf("second");
}

static void _lambda_0(void* data){

printf("first");
Run(_lambda_1, 0);
}

void F()
{
Run(_lambda_0, 0);
}


Now, to delete F, we need to delete _lambda_0 and
_lambda_1, so it is much harder do read and maintain.
The types involved are not in one place with one small
scope. This is much worst with capture.

COM interfaces are also much hard do create and maintain
compared with lambdas.






Mr Flibble

unread,
Aug 20, 2018, 6:18:10 PM8/20/18
to
On 20/08/2018 17:08, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> It looks like you're trying to do some sort of callback mechanism.
>
> IMO, callbacks in C++ are best done without function pointers, lambdas
> or std::function<>. Simply use an abstract interface that is consumed
> by the notifier and implemented by the recipient. All the crazy
> function pointer business disappears from your code, the abstract
> reads clean and there isn't any worries about ABI either. This is one
> reason why COM uses interfaces for callbacks (e.g. Connection Points).

I use COM-like interfaces in my plugin system however I disagree that
abstract interfaces are the "best" way to perform callbacks: they are
but one tool in the toolbox. Signals and slots or more recently signals
and lambdas are just as important a tool as abstract interfaces: they
tend to be more flexible especially when type erasure or generic
algorithms are involved. Forcing a user to create a class that inherits
from an interface just to be notified that the text has changed in a
widget is finicky at best and egregious at worst.

Today OOP is not the only way to design software (e.g data oriented ECS
systems) and abstract interfaces are tied to an arguably old fashioned
object oriented way of doing things.

In saying all that however "neoGFX" my upcoming C++ GUI library and game
engine uses abstract interfaces extensively (mainly in the widget
library) but it also uses other more modern methods too.

/Flibble

--
"Suppose it’s all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I’d say, bone cancer in children? What’s that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It’s not right, it’s utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates
a world that is so full of injustice and pain. That’s what I would say."

Manfred

unread,
Aug 20, 2018, 8:33:02 PM8/20/18
to
On 08/20/2018 10:16 PM, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Manfred <non...@add.invalid> spake the secret code
> <plevcl$934$1...@gioia.aioe.org> thusly:
>
>> I would not agree on this. Interface pointers are a replacement for
>> callback functions in COM because there is no such thing as a function
>> object (or pointer) in COM.
>
> Actually COM doesn't care -- a function pointer is just a data type
> and COM doesn't care about data types. It has a few well supported
> data types that don't require custom marshalling to move across object
> boundaries, but there is nothing preventing you from using COM method
> calls that accept or return function pointers.
Actually this is not correct: there is no way you can marshal a function
pointer across process boundaries in COM - this needs to end up with a
RPC call for which COM needs an interface pointer.
(In-process COM objects are functionally equivalent to DLLs, so, however
common they may be, I don't consider them representative of what COM is
for - its main value feature-wise being inter-process and inter-host
communication in my experience)

>
>> Function objects and pointers are IMO a powerful feature of C++ which,
>> as all power features, need to be known how to use properly.
>
> The function pointer syntax is painful and there are some quirks in
> the grammar as a result.
Function objects and lambdas were introduced to ease their coding,
besides other goals of course.

It's been my experience that as soon as you
> need one callback, you need a second one in short order.
That may be true, but I think it depends on the application domain.

Then there's
> the added annoyance that with function pointers you have to go through
> hoops to get the 'this' pointer passed around properly and you end up
> writing two methods on a C++ object for every callback method you
> implement -- once for a static "C" style function pointer that
> delegates to an instance method and the instance method.
If you need a 'this' pointer, then pointer-to-members are the answer;
although I have to admit that whenever there is a 'this' pointer
involved, then OOP gets more in the picture, so I find myself too
wrapping the callback into and abstract interface.

Unless
> you're required to have a C style API, it's simply easier to make an
> abstract interface that represents the contract for the interaction
> between two objects. It's also easier to create mock objects for unit
> testing if you follow this strategy.
>
>> They are essential in writing effective generic algorithms as one example.
>
> They are not essential for making generic algorithms.
I wrote /effective/ generic algorithms - stuff like std::sort works best
with function objects rather than interfaces.

Richard

unread,
Aug 21, 2018, 4:38:11 PM8/21/18
to
[Please do not mail me a copy of your followup]

Manfred <inv...@add.invalid> spake the secret code
<plfmjg$1e6v$1...@gioia.aioe.org> thusly:

>On 08/20/2018 10:16 PM, Richard wrote:
>> [Please do not mail me a copy of your followup]
>>
>> Manfred <non...@add.invalid> spake the secret code
>> <plevcl$934$1...@gioia.aioe.org> thusly:
>>
>>> I would not agree on this. Interface pointers are a replacement for
>>> callback functions in COM because there is no such thing as a function
>>> object (or pointer) in COM.
>>
>> Actually COM doesn't care -- a function pointer is just a data type
>> and COM doesn't care about data types. It has a few well supported
>> data types that don't require custom marshalling to move across object
>> boundaries, but there is nothing preventing you from using COM method
>> calls that accept or return function pointers.
>Actually this is not correct: there is no way you can marshal a function
>pointer across process boundaries in COM - this needs to end up with a
>RPC call for which COM needs an interface pointer.

You can do it with custom marshalling, which you would need because as
you say COM doesn't know how to marshall a function pointer.

Manfred

unread,
Aug 21, 2018, 5:20:04 PM8/21/18
to
On 8/21/2018 10:37 PM, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Manfred <inv...@add.invalid> spake the secret code
> <plfmjg$1e6v$1...@gioia.aioe.org> thusly:
>
>> On 08/20/2018 10:16 PM, Richard wrote:
>>> [Please do not mail me a copy of your followup]
>>>
>>> Manfred <non...@add.invalid> spake the secret code
>>> <plevcl$934$1...@gioia.aioe.org> thusly:
>>>
>>>> I would not agree on this. Interface pointers are a replacement for
>>>> callback functions in COM because there is no such thing as a function
>>>> object (or pointer) in COM.
>>>
>>> Actually COM doesn't care -- a function pointer is just a data type
>>> and COM doesn't care about data types. It has a few well supported
>>> data types that don't require custom marshalling to move across object
>>> boundaries, but there is nothing preventing you from using COM method
>>> calls that accept or return function pointers.
>> Actually this is not correct: there is no way you can marshal a function
>> pointer across process boundaries in COM - this needs to end up with a
>> RPC call for which COM needs an interface pointer.
>
> You can do it with custom marshalling, which you would need because as
> you say COM doesn't know how to marshall a function pointer.
>
Er no, not even with custom marshaling - a function callback pointer
(note: callback) is defined in the context of the address space of the
process passing the pointer. As the receiving process gets the pointer
(with custom marshaling), it would have no way to invoke the callback on
the other process - it would need to perform a COM call which requires
an interface pointer.

Richard

unread,
Aug 21, 2018, 6:34:36 PM8/21/18
to
[Please do not mail me a copy of your followup]

Manfred <non...@add.invalid> spake the secret code
<plhvlj$11j2$1...@gioia.aioe.org> thusly:
You basically do it by brewing up remote transparency for a local
function pointer yourself. At any rate, I don't see the point in
delving further into this discussion since it is way off tangent for
the original topic.
0 new messages