Error trying to pass function as argument

Hello!

I'm having a problem passing a function as an argument, to another function.

Consider the following class:
1
2
3
4
5
6
7
8
class Foo
{
    public:
        void display_something()
        {
            std::cout << "Something";            
        }
};

Now consider this second class:
1
2
3
4
5
6
7
8
class Bar:
{
    public:
        void output(void (*display)())
        {
            display();
        }
};


Now this is illustrated and simplified but my problem is similar to what happens here in main:
1
2
3
4
5
6
7
int main()
{
    Foo f;
    Bar b;
    
    b.output(f.display_something);
}


Using VS 19, on line 6 I get an error saying 'Console_Display::display_loading_bar': non-standard syntax; use '&' to create a pointer to member (here Console_Display being Foo)

Any help would be much appreciated, thanks in advance!
Last edited on
There's something of a conceptual issue here; any given non-static class member function expects to be called on an instance of that class. You can think of it as every non-static class member function has a hidden variable, which is a pointer to the class object you're calling it on.

You could think of it as this:
f.display_something()
is kind of like this:
Foo::display_something(Foo* this)

So you see, f.display_something doesn't refer to a function in a specific Foo object. It refers to the function that is used by all Foo objects, to which there is a hidden variable passed.

One option is to make the function static:

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
#include <iostream>
using namespace std;

class Foo
{
    public:
        static void display_something()
        {
	  std::cout << "Something" << '\n';            
        }
};

class Bar
{
    public:
        template <typename T>
        void output(T function)
        {
            function();
        }
};

int main()
{
    Foo f;
    Bar b;
    b.output(Foo::display_something);
}


Would that do what you need?




If you’re really keen of weird syntax, I’ve found the following alternative solution here
https://stackoverflow.com/questions/12662891/how-can-i-pass-a-member-function-where-a-free-function-is-expected
that avoids static members (there’re explanations about how this syntax works at the linked page).
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
#include <iostream>


class Foo {
public:
    void display_something();
};


void Foo::display_something()
{
    std::cout << "Something\n";
}


class Bar {
public:
    void output( void (Foo::*display)(), Foo& foo );
};


void Bar::output( void (Foo::*display)(), Foo& foo )
{
    (foo.*display)();
}


int main()
{
    Foo f;
    Bar b;
    b.output( f.display_something, f );
}


Output:
Something

- - -
But why did you give us three distinct pieces of code instead of putting them all together?
Wouldn’t it have been simpler to just write:
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
class Foo
{
    public:
        void display_something()
        {
            std::cout << "Something";            
        }
};

class Bar:
{
    public:
        void output(void (*display)())
        {
            display();
        }
};

int main()
{
    Foo f;
    Bar b;
    
    b.output(f.display_something);
}

instead of «Consider the following class: … Now consider this second class: …»?
What’s bad in providing a compilable example? You’d have immediately spotted the colon after class Bar.

- - -
EDIT:
Note: main() can also become more readable:
1
2
3
4
5
6
int main()
{
    Foo f;
    Bar b;
    b.output( &Foo::display_something, f );
}

Last edited on
Sorry for the late reply guys, I've been drowned in work..

@Repeater

Thanks, that helps a ton since I'm not familiar with such syntax at all. Although I can't really make the function static since it's tied to a variable within the class and needs to interact with it for each call.

@Enoizat

Thank you for that indeed odd looking solution, syntax-wise. I'll try to implement it in my program asap. Would you however know how to the same thing without having to pass class-specific objects to the function? I would have to include my class header 2 more times and I'm concerned about circular dependency?

But why did you give us three distinct pieces of code instead of putting them all together?
For some mysterious reason really, I wrote this quickly without opening an editor. My bad for the missing colon after class Bar.

Thanks a lot!
Last edited on
Well, with your solution Eniozat, I'm getting the same exact error : error C3867: 'Console_Display::display_loading_bar': non-standard syntax; use '&' to create a pointer to member doesn't seem to be doing anything different, at least in my case :/

I think the whole point of me trying to do this was not having to pass the class object to the function and simply passing a function. I guess passing the class object as an argument and then calling the function from the function would work, I'll try that
Last edited on
I think the whole point of me trying to do this was not having to pass the class object to the function and simply passing a function.

What you can do is synthesize a stateful function object - that is, a closure over f which calls f.display_function(). Closure objects can be generated by hand, with lambda expressions, or with a library function like std::bind.

You have a few choices for the signature of your output function. The simplest choice is to accept a std::function, although I might typically prefer to make output a function template.

The most complicated and least-flexible choice is to handle member function pointers yourself. See output2 for an example.

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
#include <functional> 
#include <iostream>
#include <memory>

struct A { int f() const { return x_; } int x_ = 40; };

template <typename T> void output0(T fn) { std::cout << fn(); } 

void output1(std::function<int()> fn) { std::cout << fn(); }

void output2(int (A::*pmf)() const, A* implicit_object_ptr)
{ std::cout << (implicit_object_ptr->*pmf)(); }

int main() 
{
    A a; 
    
    output0([a]() { return a.f(); });
    std::cout << '\n';
    
    output1(std::bind(&A::f, std::addressof(a)));
    std::cout << '\n';
    
    output2(&A::f, std::addressof(a));
    std::cout << '\n';
}


I did write a little bit about std::function yesterday; maybe you will find it helpful: http://www.cplusplus.com/forum/general/267001/
Consider using templated call backs (it offers a lot more flexibility). For example:

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
#include <iostream>
#include <functional>
#include <cstdio>
#include <string>

struct foo
{
    void display() { std::cout << "foo::display()\n" ; history += " display," ; }
    void display2( int a, double b )
    { std::cout << "foo::display2(" << a << ',' << b << ")\n" ; history += " display2," ; }

    std::string history = "call history:" ;
};

struct bar
{
    template < typename CALLABLE, typename... ARGS >
    decltype(auto) call_it( CALLABLE&& fn, ARGS&&... args ) const
         noexcept( std::is_nothrow_invocable<CALLABLE,ARGS...>::value )
    {
        std::cout << "bar::call_it => " ;

        // https://en.cppreference.com/w/cpp/utility/functional/invoke (C++17)
        // https://en.cppreference.com/w/cpp/utility/forward
        return std::invoke( std::forward<CALLABLE>(fn), std::forward<ARGS>(args)... ) ;
    }
};

int main()
{
    foo object ;

    const bar b ;
    b.call_it( std::puts, "hello there!" ) ; // call non-member function

    // call member functions
    b.call_it( &foo::display, object ) ;
    b.call_it( &foo::display2, object, 2345, 67.89 ) ;
    b.call_it( &std::ostream::write, std::cout, "abcdefgh\n", 9 ) ;

    // use a lambda expression (call a closure object)
    b.call_it( []( auto&& x ) { std::cout << x << '\n' ; }, "hello again!" ) ;

    // access a (public) member variable!
    std::cout << b.call_it( &foo::history, object ) << '\n' ;

    // call a function object
    std::cout << b.call_it( std::plus<>{}, std::string("bye "), "for now!" ) << '\n' ;
}

http://coliru.stacked-crooked.com/a/5cce129c12b40bb3
https://rextester.com/QVG22662
@mbozzi
Holy, this looks very unfamiliar to me - not to say alien - haha. I'll do my homework and dig the link you provided as well as the memory header which I've actually never seen used! Thanks so much for your time!

@JOBorges
I'm going to tell you the same as I did to mbozzy :-), this is very much unfamiliar to me and I'm going to have to need to look at some ressource to understand what's going on there. I'll let you know If I need some further enlightenment! Thanks you so much as well!

Update on my project: Well I've temporally sorted the issue by passing a class object as an argument and calling the class function within the function with the object. Although I would really like to pass a function instead to avoid what seem to be unnecessary includes so I'm not giving up so far! :-)
I can't really make the function static since it's tied to a variable within the class and needs to interact with it for each call.
the whole point of me trying to do this was not having to pass the class object to the function

You can't have it both ways. If the function interacts with a (non-static) class member, then you must somehow tell it which instance to interact with. It can't divine the instance itself.
I suggest focusing on this. In my opinion, it is the most fundamental of the options discussed so far:
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

struct A { int f() const { return x_; } int x_ = 40; };
template <typename T> 
void output(T fn) { std::cout << fn() << '\n'; }

int main() 
{
    A a; 
    output([a]() { return a.f(); }); 
}


output is a function template and [a]() { return a.f(); } is a lambda expression. A lambda expression is a nameless object of a unique class type that acts like a function.

That function has access to a copy of the object a in the surrounding scope (the one on line 14: the lambda expression is a closure over a: https://en.wikipedia.org/wiki/Closure_(computer_programming) )
[a]() { return a.f(); }
It acts like a function of no parameters
[a]() { return a.f(); }
It acts like a function whose body is { return a.f(); } ; the function returns whatever type the expression a.f() happens to have.
[a]() { return a.f(); }

IMO you shouldn't spend much time studying member function pointers. They are very idiosyncratic and really aren't important unless you're specifically interested in this aspect of C++. OTOH entire programming languages are built around the concepts modeled by lambda expressions and templates. Those are definitely worth your time.

Good luck!
You can't have it both ways. If the function interacts with a (non-static) class member, then you must somehow tell it which instance to interact with. It can't divine the instance itself.
Thanks for pointing this out, only now do I realise the foolishness of my question :)

IMO you shouldn't spend much time studying member function pointers. They are very idiosyncratic and really aren't important unless you're specifically interested in this aspect of C++. OTOH entire programming languages are built around the concepts modeled by lambda expressions and templates. Those are definitely worth your time.
I'll surely look into those thanks!

Thank you so much for your time guys, it is much appreciated! <3
Registered users can post here. Sign in or register to post.