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

Default arguments with std::function

31 views
Skip to first unread message

JiiPee

unread,
Sep 16, 2017, 6:24:03 AM9/16/17
to
void foo(int a=6) {}


std::function<void(int)> f;

f(); // does not work


How can I create a fuction object which understands default arguments?
like I would like to call here f(); but this does not compile. Thanks you

Öö Tiib

unread,
Sep 16, 2017, 7:28:51 AM9/16/17
to
Perhaps I do not understand your problem but callability of object is
implemented as operator() so all what you need is to have default
argument of operator() of your function object:

int main()
{
struct F
{
void operator()(int a = 6) {}
} f;

f();

f(42);
}

JiiPee

unread,
Sep 16, 2017, 7:33:26 AM9/16/17
to
Thanks, something to try. But I think I really need to use this
std::function here, because the real problem i have is to use it with
templates, so I need to use std::function in my code. Your example does
not use std::function.

In my real code i have something like:

function f = foo<1>;

and foo is a template function with default parameters.

So i want to use f:

f(1);

f();

SG

unread,
Sep 16, 2017, 9:07:48 AM9/16/17
to
Am Samstag, 16. September 2017 13:33:26 UTC+2 schrieb JiiPee:
>
> Thanks, something to try. But I think I really need to use this
> std::function here, because the real problem i have is to use it with
> templates, so I need to use std::function in my code.

That does not sound like an explanation for why you need std::function.

> In my real code i have something like:
>
> function f = foo<1>;
>
> and foo is a template function with default parameters.
>
> So i want to use f:
>
> f(1);
>
> f();

OK. But--as you know--it doesn't work. If f is of type
std::function<void(int)> it will have the following function call
operator:

void operator()(int) const;

and there is no default argument there, regardless of how you
initialize this function object. Now, you could write your own functor
like this:

struct myfunction {
std::function<void(int)> inner;

void operator()(int i=6) const { return inner(i); }
};

But this 6 here is a static property of myfunction. As such, you can't
change it at runtime and it doesn't depend on how yo initialize inner.
If you want to support changing default arguments you could do:

struct myfunction {
std::function<void(int)> inner;
int current_default;

void operator()(int i) const { return inner(i); }
void operator()() const { return inner(current_default); }
};

But C++ doesn't let you access default arguments. So, if you have

void foo(int = 6);

there is no way of extracting the default argument of foo. The only
way of making use of this default argument is by calling the function
directly by name without arguments. That's it. So, you would have to
replicate the default argument where you initialize myfunction:

myfunction mf = { &foo, 6 };
mf();
mf(42);

I don't see a way around it -- unless perhaps you *always* expect
there to be a default argument, in which case you *could* do this:

void foo(int = 6);

struct myfunction {
std::function<void()> inner1;
std::function<void(int)> inner2;

void operator()() const { return inner1(); }
void operator()(int i) const { return inner2(i); }
};

int main() {
myfunction mf = { []{foo();}, foo };
mf();
mf(42);
}

Here, foo is directly used within the lambda expression and without
an explicit argument. This makes the compiler lookup what foo is. It
finds the above declaration with the default argument and basically
turns the call foo() into foo(6) under the hood.

But ... you don't really wanna do that! Try to avoid it if possible.

Cheers!
sg

JiiPee

unread,
Sep 16, 2017, 9:42:55 AM9/16/17
to
On 16/09/2017 14:07, SG wrote:
> myfunction mf = { &foo, 6 };
> mf();
> mf(42);


interesting idea. thanks. Seems like operator() is the way to go. I ll
play around with these

Alf P. Steinbach

unread,
Sep 16, 2017, 12:02:37 PM9/16/17
to
There is as far as I know no way to obtain the argument default values
programmatically.

As soon as you pass a stand-alone function around, even as a template
parameter, information about the argument defaults is lost.

However, when the original function is a member function of a class, a
functor, that /type/ can be passed around, and the function can then be
called with defaults:


#include <iostream>
#include <memory> // std::(unique_ptr, make_unique)
#include <utility> // std::move
using namespace std;

struct Foo
{
void action( int const a = 6 ) const { cout << "Foo " << a << endl; }
};

struct Bar
{
void action( int const a = 6 ) const { cout << "Bar " << a << endl; }
};

template< class Some_type > struct Type_carrier_ {};

struct Abstract_callable
{
virtual void action() const = 0;
virtual void action( int ) const = 0;
virtual auto clone() const -> unique_ptr<Abstract_callable> = 0;
};

template< class Type >
struct Specific_callable
: Abstract_callable
{
void action() const override { Type{}.action(); }
void action( int const a ) const override { Type{}.action( a ); }

auto clone() const
-> unique_ptr<Abstract_callable>
override
{ return unique_ptr<Abstract_callable>{ new Specific_callable{
*this } }; }
};

class Callable
{
private:
unique_ptr<Abstract_callable> impl_;

public:
void operator()() const { impl_->action(); }
void operator()( int const a ) const { impl_->action( a ); }

template< class Action_provider >
Callable( Type_carrier_<Action_provider> )
: impl_{ make_unique< Specific_callable< Action_provider > >() }
{}

Callable( Callable const& other )
: impl_{ other.impl_->clone() }
{}

Callable( Callable&& other )
: impl_{ move( other.impl_ ) }
{}
};

void do_stuff( Callable const& f )
{
f();
f( 42 );
}

auto main()
-> int
{
do_stuff( Callable{ Type_carrier_<Foo>{} } );
do_stuff( Callable{ Type_carrier_<Bar>{} } );
}


The key point of this code being that `Callable` is a concrete,
non-templated type whose instances carry the requisite knowledge.

Instead of separate `operator()` implementations in `Callable`, you can
just define a single templated one that forwards its arguments.


Cheers & hth.,

- Alf
0 new messages