Functor with default parameters.

Hi guys,

Short version: Is there a way to pass a functor/bind a function with one or more of the parameters fixed?

e.g. Function takes a functor of a function returning with two doubles as parameters, and returning a double. I want to pass functions to it that have more parameters, but where the 3rd and further parameters have a fixed value.

Something like:
double myFunction(double a, double b) = double myOtherFunction(double a, double b, double c = 50.0, double d = 2.1);
So that I can pass different functions with different number of parameters as a parameter in a "standard form"?

Long version:

I have a set of objective functions that take multiple parameters, the first two of which define a movement and the others define a "scenario". Those functions are passed as a parameter to other functions that perform an analysis or optimization using that function as objective. Within that optimization, only the first two parameters of the objective function will ever change; the other parameters are basically a "configuration" of the function. Calling the analysis/optimization functions is basically saying "Now perform the analysis in the scenario where Parameter3 = 5 and Parameter4 = 10".

Now, I have to pass the other parameters into the analysis function call, which is bothersome because not all objective functions take the same amount of parameters and I intend to add additional parameters later on. I want to be able to pass a single "standardized form" function taking only the first two parameters, fixing the other parameters on beforehand.

e.g. I want to be able to pass the following functions as if they were the same:

1
2
3
4
5
double firstFunction(double a, double b) = double myActualFunction(double a, double b, double c = 50.0, double d = 2.1);
double secondFunction(double a, double b) = double myOtherActualFunction(double a, double b, int t = 5, int u = 90, double c = 2.6);

PerformAnalysis(firstFunction);
PerformAnalysis(secondFunction);


What are some ways to do this?
GCC allows default parameters, but I thought they weren't allowed. And GCC doesn't allow it with -std=c++11 -pedantic set, so I think they know it shouldn't be allowed.

As for providing code to help you, you haven't posted a functor.
Last edited on
One way would be to overload the function to provide a version with only two doubles as arguments.

Lambdas or configurable function objects would probably be the most flexible.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// http://ideone.com/nJdS76
#include <functional>
#include <iostream>

double function_a(double a, double b, double c, double d)
{
    std::cout << "function_a(" << a << ", " << b << ", " << c << ", " << d << ")\n";
    return a;
}

double function_b(double a, double b, int t, int u, double c)
{
    std::cout << "function_b(" << a << ", " << b << ", " << t << ", " << u << ", " << c << ")\n";
    return a;
}

struct second_func
{
    second_func(int t, int u, double c) :t(t), u(u), c(c) {}

    double operator()(double a, double b) { return function_b(a, b, t, u, c); }

    int t;
    int u;
    double c;
};


void PerformAnalysis(std::function<double(double, double)> func)
{
    func(4.0, 5.0);
}

int main()
{
    auto first_func = [](double a, double b) { return function_a(a, b, 60.0, 2.1); };

    // or:
    // double c = 60.0;
    // double d = 1.2;
    // auto first_func = [=](double a, double b) { return function_a(a, b, c, d); };

    PerformAnalysis(first_func);
    PerformAnalysis(second_func(5, 90, 2.6));
}


And, of course, there's always std::bind...
Last edited on
Make the functor's operator() virtual. Then create derived classes that contain the other parameters as class members.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>

class Functor {
public:
    virtual double operator() (double a, double b) = 0;
    };

class firstFunctor : public Functor {
public:
    firstFunctor(double c_in, double d_in) :
        c(c_in), d(d_in) {}
    virtual double operator() (double a, double b) {
        return a*c + b*d;
    }

    double c,d;
};

class secondFunctor : public Functor {
public:
    secondFunctor(double t_in, double u_in, double c_in) :
        t(t_in), u(u_in), c(c_in) {}

    virtual double operator() (double a, double b) {
        return a*t + b*u + c;
    }

    double t, u, c;
};

void PerformAnalysis(Functor &f)
{
    std::cout << f(0,0) << ' ' << f(0.5, 2.3) << '\n';
}

int main()
{
    firstFunctor f1(3, 5);
    secondFunctor f2(1.5, 2.5, 3.5);
    PerformAnalysis(f1);
    PerformAnalysis(f2);
    return 0;
}

0 13
3.5 10

Thanks, dhayden!

In retrospect I realize I may have used the wrong terminology (I was using function pointers, not function objects), but your solution is much clearer and flexible than mine. It even allows me to add additional options by overloading the () operator.

Marking as solved. Thanks!
Oh, missed the posts by kbw and cire; my bad!

@kbw: My function pointers are defined like this:
typedef double (SomeClass::*Func)(double a, double b) const;

With the analysis/optimization functions taking a Func "object" as parameter. However, I want to pass "alternately configured" versions too; eg. functions that have a 3rd parameter that influences the result of the call, but stays constant during the function call of the analysis/optimization.

@cire: The lambda notation is what I roughly had in mind, but I wasn't sure of the syntax. Thanks! Ultimately I'm going with configurable function objects, because I think they may be easier to read and understand for outsiders.
> void PerformAnalysis(Functor &f)

As far as possible, callable objects should not rely on object identity, they should be passed by value. Standard algorithms rely on this behaviour.
[Note: Unless otherwise specified, algorithms that take function objects as arguments are permitted to copy those function objects freely. Programmers for whom object identity is important should consider using a wrapper class that points to a noncopied implementation object such as reference_wrapper<T>, or some equivalent solution. —end note ] - IS

Details: Item 38 Design functor classes for pass-by-value. (Scott Meyers, Effective STL)


> virtual double operator() (double a, double b) = 0;

In any case, as far as possible, the call operator should be a const member.

PerformAnalysis( firstFunctor(3,5) ) ; // **** error: can't seat lvalue reference on prvalue
http://coliru.stacked-crooked.com/a/cd3074bd0db94b07


I would strongly favour the approach suggested by cire. Something along these lines:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <functional>

double PerformAnalysis( std::function< double(double,double) > fn ) { return fn( 1.2, 3.4 ) ; }

template < typename FN, typename... MORE_ARGS >
std::function< double(double,double) > make_binary( FN&& fn, MORE_ARGS&&... more_args )
{
    using namespace std::placeholders ;
    return std::bind( std::forward<FN>(fn), _1, _2, std::forward<MORE_ARGS>(more_args)... ) ;
}

double myActualFunction( double a, double b, double c = 50.0, double d = 2.1 )
{
    std::cout << "myActualFunction( " << a << ", " << b << ", " << c << ", " << d << " )\n" ;
    return a+b+c+d ;
}

double myOtherActualFunction( double a, double b, int t = 5, int u = 90, double c = 2.6 )
{
    std::cout << "myOtherActualFunction( " << a << ", " << b << ", " << t << ", " << u << ", " << c << ")\n" ;
    return a+b+t+u+c ;
}

int main()
{
    const std::function< double(double,double) > my_functions[]
    {
        make_binary( myActualFunction, 50.0, 2.1 ),
        make_binary( myOtherActualFunction, 5, 90, 2.6 ),
        make_binary( myOtherActualFunction, 99, 123, 0.4 ),
        make_binary( myActualFunction, -1.2, -3.45 ),
        []( double a, double b ) { std::cout << "main::closure( " << a << ", " << b << " )\n" ; return a+b ; },
        []( double a, double b ) { return myActualFunction( a, b, 5.6, 7.8 ) ; },
    } ;

    for( const auto& fn : my_functions ) PerformAnalysis(fn) ;
}

http://coliru.stacked-crooked.com/a/87ff02347ea7544f
Hey JLBorges,

Thanks for the input! Your way is much closer to what I had in mind than the others; I had absolutely no idea about all the syntax you just put up. I'm glad I hadn't implemented any of the other suggestions yet; this one is so close to the usage of my old method that I can replace it in mere minutes.

(PS: Apparently someone reported your post?)

One question: how does this work with class/private functions? All of the function binding will, most likely, be limited to one class, so for now I've just made the make_binary function also part of that class, but I may want to step away from that at some point.
Last edited on
> how does this work with class/private functions?

A private member function can be accessed by name only by members or friends of the class.
However, there is no access control for members accessed through an alias; make_binary() need not be a member or friend of the class. The situation is no different from:

1
2
3
4
5
6
7
struct A 
{
     private: int value ; // only members and friends can access 'value' by name
     
     // the private member can be accessed through the returned alias everywhere
     public: const int& alias() const { return value ; } 
};


For instance:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <functional>

double perform_analysis( std::function< double(double,double) > fn ) { return fn( 1.2, 3.4 ) ; }

template < typename FN, typename... MORE_ARGS >
std::function< double(double,double) > make_binary( FN&& fn, MORE_ARGS&&... more_args )
{
    using namespace std::placeholders ;
    return std::bind( std::forward<FN>(fn), _1, _2, std::forward<MORE_ARGS>(more_args)... ) ;
}

struct my_class
{
    auto analysis_fn_a() const // note: return type deduction with auto is C++14
    {
        using namespace std::placeholders ;
        // non-static member function: requires an object
        return std::bind( &my_class::private_memfn_a, this, _1, _2, _3, _4 ) ; // bind this object
    }

    private:
        double private_memfn_a( double a, double b, int t , double c ) const
        {
            std::cout << "my_class::private_memfn( " << a << ", " << b << ", " << t << ", " << c << " )\n" ;
            return a+b+c+v ;
        }

        int v = 7 ;
};

int main()
{
    my_class my_object ;
    perform_analysis( make_binary( my_object.analysis_fn_a(), 23, 9.4 ) ) ;
    perform_analysis( make_binary( my_object.analysis_fn_a(), -6, 78.2 ) ) ;
}

http://coliru.stacked-crooked.com/a/6dc9b4c4aaaf9c04

That was expositional; the code would perhaps be simpler if we did this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <functional>

double perform_analysis( std::function< double(double,double) > fn ) { return fn( 1.2, 3.4 ) ; }

struct my_class
{
    auto bound_analysis_fn_a( int t, double c ) const // note: return type deduction with auto is C++14
    {
        using namespace std::placeholders ;
        // non-static member function: requires an object
        return std::bind( &my_class::private_memfn_a, this, _1, _2, t, c ) ; // bind this object and the extra args
    }

    private:
        double private_memfn_a( double a, double b, int t , double c ) const
        {
            std::cout << "my_class::private_memfn( " << a << ", " << b << ", " << t << ", " << c << " )\n" ;
            return a+b+c+v ;
        }

        int v = 7 ;
};

int main()
{
    my_class my_object ;
    perform_analysis( my_object.bound_analysis_fn_a( 23, 9.4 ) ) ;
    perform_analysis( my_object.bound_analysis_fn_a( -6, 78.2 ) ) ;
}

http://coliru.stacked-crooked.com/a/7c2042736c8baa0f
Thanks again for the explanation!

I'm a bit confused by the "this":
return std::bind( &my_class::private_memfn_a, this, _1, _2, _3, _4 ) ;

I understand why it's necessary (my function pointers also required the object), but I don't know how it works. I couldn't find anything about it in the reference material of std::bind. Why isn't calling it as a member function of my_object enough? How does std::bind "know" that it has to treat the first parameter as the object to which the function belongs?
How does std::bind "know" that it has to treat the first parameter as the object to which the function belongs?

Because the first thing fed to std::bind is a pointer-to-member-function.

http://stackoverflow.com/a/15264126
Ah, so basically there are two signatures for the std::bind function, one that takes a pointer-to-function and some set of parameters, and one that takes a pointer-to-member-function, a pointer-to-object and a set of parameters? I'm not even going to ask how the distinction is made; this is a bit too complex for me.

Anyway, thanks for the detailed answers! Got exactly what I was looking for and learned some neat new tricks!

P.S. Just noticed it actually is in the reference material; I was expecting it to be in the list of function signatures at the top, but it's under the "Return value" section.
If fn is a pointer to member, the first argument expected by the returned function is an object of the class *fn is a member (or a reference to it, or a pointer to it).

> so basically there are two signatures for the std::bind function,
> one that takes a pointer-to-function and some set of parameters,
> and one that takes a pointer-to-member-function, a pointer-to-object and a set of parameters?

In this case, some jargon (definitions in the standard) actually helps.
Function objects
A function object type is an object type that can be the type of the postfix-expression in a function call.
A function object is an object of a function object type.
In the places where one would expect to pass a pointer to a function to an algorithmic template, the interface is specified to accept a function object. This not only makes algorithmic templates work with pointers to functions, but also enables them to work with arbitrary function objects.

A callable type is a function object type or a pointer to member. A callable object is an object of a callable type.


std::bind() can bind any callable object (pointers to functions, pointers to member functions, closures, objects of a user-defined type with an overloaded call operator, the polymorphic call wrapper std::function<>, the result of another bind expression) and it returns a forwarding call wrapper (a bind-expression). Needless to say, the call wrapper is itself a callable object.

A call wrapper type is a type that holds a callable object and supports a call operation that forwards to that object. A call wrapper is an object of a call wrapper type. - IS


std::function<> is the polymorphic call wrapper "which encapsulates arbitrary callable objects."

With these, the code becomes very idiomatic, very flexible. For instance:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <functional>
#include <iomanip>
#include <memory>

struct A
{
    int member_fun( int a, int b, int c ) const
    {
        std::cout << "A::member_fun( " << a << ", " << b << ", " << c << " )\n" ;
        return a + b + c + v ;
    }

    int v = 5 ;
};

long non_member_fun( const A& object, double a, char b, short c )
{
    std::cout << "non_member_fun( " << a << ", " << +b << ", " << c << " )\n" ;
    return a + b + c + object.v ;
}

struct functor
{
    double operator() ( const A* object, double a, double b, double c ) const
    {
        std::cout << "functor::operator() ( " << a << ", " << b << ", " << c << " )\n" ;
        return a + b + c + object->v ;
    }
};

const auto closure = [] ( const A* object, unsigned short a, long long b, wchar_t c ) -> unsigned long long
{
    std::cout << "closure( " << a << ", " << b << ", " << +c << " )\n" ;
    return a + b + c + object->v ; ;
};

int main()
{
    using namespace std::placeholders ;
    A a ;

    std::function< int(int,int,int) > call_wrapper ;

    // pass wrapped reference to object
    const auto fn = std::bind( &A::member_fun, std::ref(a), _2, _3, _1 ) ;
    fn( 1, 2, 3 ) ; // A::member_fun( 2, 3, 1 )

    // pass copy of object
    std::bind( &A::member_fun, a, _2, _3, _1 )( 1, 2, 3 ) ; // A::member_fun( 2, 3, 1 )

    call_wrapper = fn ;
    call_wrapper( 1, 2, 3 ) ; // A::member_fun( 2, 3, 1 )

    call_wrapper = std::bind( non_member_fun, std::ref(a), _3, _2, _1 ) ;
    call_wrapper( 1, 2, 3 ) ; // non_member_fun( 3, 2, 1 )

    call_wrapper = std::bind( functor(), std::addressof(a), _3, _1, _2 ) ;
    call_wrapper( 1, 2, 3 ) ; // functor::operator() ( 3, 1, 2 )

    call_wrapper = std::bind( closure, std::addressof(a), _1, _3, _2 ) ;
    call_wrapper( 1, 2, 3 ) ; // closure( 1, 3, 2 )

    const auto fn2 = std::bind( call_wrapper, _1, _1, _1 ) ;
    fn2(4) ; // closure( 4, 4, 4 )

    // pass smart pointer to object
    std::function< void(short,double) > fn3 = std::bind( &A::member_fun, std::make_shared<A>(), _1, 99, _2 ) ;
    fn3(4,5) ; // A::member_fun( 4, 99, 5 )
}

http://coliru.stacked-crooked.com/a/2b582872a94ea69f
I will be rereading that post once I've absorbed a few more reference pages on <functional>'s many tools. Is there a "dummy's introduction to the Standard" somewhere? I'm starting to notice my lack of knowledge is hurting my ability to properly express my questions.
Topic archived. No new replies allowed.