function_ref

270 views
Skip to first unread message

Avi Kivity

unread,
Dec 9, 2016, 9:19:42 AM12/9/16
to ISO C++ Standard - Future Proposals
Often, one wants to call a function with a one-off callback. There are
currently three ways to do this:


1. templates


template <typename Func> // void (int, int)

void foo(int a, int b, Func func);


The problem here is that foo's definition must be available, and there
is an increase in compile time, executable size, and the odds of seeing
a cryptic error (to be reduced with concepts).


2. std::function


void foo(int a, int b, std::function<void (int, int)> func);


We've solved the problems of the template above, but added a virtual
function call, an allocation (which can be avoided be the
implementation, sometimes), and a requirement that the lambda we send
here be copyable; if we pass func down the line, we add either extra
indirection or extra copies/allocations.


3. custom abstract class


class foo_callback {

public:

virtual ~foo_callback() {} // not really necessary

virtual void call(int, int) const = 0;

};


void foo(int a, int b, const foo_callback& func);


This is the C++98 way; it is very verbose for the caller, but avoids any
allocation for the caller, and can be passed efficiently downstream.


I'm proposing a fourth way, std::function_ref. It acts like
std::function, but only refers to a function; it does not capture the
value. It is the responsibility of the caller to ensure the function is
alive.


void foo(int a, int b, std::function_ref<void (int a, int b)> func);


Here's a sample program:


void sum_and_report(int a, int b, function_ref<void (int sum)> report) {
report(a + b);
}

int main(int ac, char** av) {
int sum;
sum_and_report(2, 2, [&] (int result) {
sum = result;
});
return sum == 4 ? 0 : 1;
}

and here's an example implementation:


template <typename Ret, typename... Args>
class function_ref<Ret (Args...)> {
using thunk_type = Ret (*)(const function_ref*, Args...);
const void* _lambda;
thunk_type _thunk;
public:
template <typename Lambda>
function_ref(const Lambda& lambda)
: _lambda(&lambda) {
_thunk = thunk_type([] (const function_ref* zis, Args... args) {
auto lambda = static_cast<const Lambda*>(zis->_lambda);
return (*lambda)(std::move(args)...);
});
}
Ret operator()(Args... args) const {
return _thunk(this, std::move(args)...);
}
};


Zhihao Yuan

unread,
Dec 9, 2016, 10:36:38 AM12/9/16
to std-pr...@isocpp.org
On Fri, Dec 9, 2016 at 8:19 AM, Avi Kivity <a...@scylladb.com> wrote:
>
> I'm proposing a fourth way, std::function_ref. It acts like std::function,
> but only refers to a function; it does not capture the value. It is the
> responsibility of the caller to ensure the function is alive.
>
>
> void foo(int a, int b, std::function_ref<void (int a, int b)> func);

See also http://blog.miator.net/post/141640032964/take-callable-by-signature-rargs
, with a few changes on top of the LLVM function_ref. Not proposed
yet, but I think it's a good idea.

--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://blog.miator.net/

D. B.

unread,
Dec 9, 2016, 11:13:06 AM12/9/16
to std-pr...@isocpp.org
I thought that std::function combined with std::reference_wrapper would already handle this case. Where does it fall short?

Avi Kivity

unread,
Dec 9, 2016, 11:20:11 AM12/9/16
to std-pr...@isocpp.org
It allocates (perhaps conditionally in some implementations).

On Dec 9, 2016 18:13, "D. B." <db0...@gmail.com> wrote:
I thought that std::function combined with std::reference_wrapper would already handle this case. Where does it fall short?

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CACGiwhFkvr%2BT2EMK_GdrmXZWa6JehgD%2BmNf7HqXzOrckJ%2B3uMw%40mail.gmail.com.

Avi Kivity

unread,
Dec 9, 2016, 11:31:10 AM12/9/16
to std-pr...@isocpp.org
Yes, llvm function_ref and mine are very similar. So it looks like there's a case for standardization.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Dec 9, 2016, 11:32:08 AM12/9/16
to ISO C++ Standard - Future Proposals
On Friday, December 9, 2016 at 11:13:06 AM UTC-5, D. B. wrote:
I thought that std::function combined with std::reference_wrapper would already handle this case. Where does it fall short?

1. There's no way to prevent someone from passing something that isn't bound in `reference_wrapper`.

2. The combination of `function` with `reference_wrapper` is not particularly obvious. As such, it will primarily be used by experts, rather than lay C++ users.

Nicol Bolas

unread,
Dec 9, 2016, 11:33:23 AM12/9/16
to ISO C++ Standard - Future Proposals
On Friday, December 9, 2016 at 11:20:11 AM UTC-5, Avi Kivity wrote:
It allocates (perhaps conditionally in some implementations).

From the standard:

>  shall not throw exceptions if f ’s target is a callable object passed via reference_wrapper or a function pointer.

So it's not allowed to allocate memory.

Avi Kivity

unread,
Dec 9, 2016, 5:46:01 PM12/9/16
to std-pr...@isocpp.org
Interesting.  That makes the proposal less compelling.

Zhihao Yuan

unread,
Dec 10, 2016, 1:13:29 AM12/10/16
to std-pr...@isocpp.org
On Fri, Dec 9, 2016 at 4:45 PM, Avi Kivity <a...@scylladb.com> wrote:
>
> Interesting. That makes the proposal less compelling.

This is arguable. function_ref as a vocabulary type, embeds the
meaning of non-owning into the type itself rather than ask the
caller side to choose, IMO is semantically independent,
regardless of lots of other advantages in terms of compilation
time, codegen, etc.

Avi Kivity

unread,
Dec 10, 2016, 4:19:05 AM12/10/16
to std-pr...@isocpp.org
On 12/10/2016 08:13 AM, Zhihao Yuan wrote:
> On Fri, Dec 9, 2016 at 4:45 PM, Avi Kivity <a...@scylladb.com> wrote:
>> Interesting. That makes the proposal less compelling.
> This is arguable. function_ref as a vocabulary type, embeds the
> meaning of non-owning into the type itself rather than ask the
> caller side to choose, IMO is semantically independent,
> regardless of lots of other advantages in terms of compilation
> time, codegen, etc.
>

I'm not saying the proposal is worthless, just that it is less
compelling. It still has advantages over function_ref, but they are
smaller than what I thought they were.

Reply all
Reply to author
Forward
0 new messages