RexYuan
RexYuan

Reputation: 300

How to pass non-static member function as template argument to another member function?

I want to do something like this:

struct S
{
   void mf() {};

   template <auto f>
   void func()
   {
      f();
   }
};

int main()
{
   S x;
   x.func<x.mf>();
}

However, these are the errors:

error: no matching function for call to 'S::func<x.S::mf>()'`
note: candidate: 'template<auto f> void S::func()'
note:   template argument deduction/substitution failed:
error: could not convert 'x.S::mf' from '<unresolved overloaded function type>' to 'void (S::*)()'

I am not sure I understand what I am doing wrong.

Why is x.mf not resolved since I already instantiated x? And how do I make this work?

Upvotes: 1

Views: 1478

Answers (3)

JeJo
JeJo

Reputation: 32847

Why is x.mf not resolved since I already instantiated x?

Because it is not a valid syntax. There you need to mention the member function by operator &, meaning you should have

x.func<&S::mf>();
//    ^^^^^^^^

So that the template parameter will be deduced to a corresponding member function pointer. That is void(S::*)().


How do I make this work?

The second problem is, the function call f() should have been a call through a member function pointer. This is different than the normal function call.

The traditional way of calling the member function pointer with the instance is

(this->*f)();

However, since this is more convenient way using more generic liberary function, so calledstd::invoke from <functional> header.

Meaning you could do more readable call through a member function pointer like.

#include <functional> // std::invoke

template <auto f>
void func()
{
   std::invoke(f, this);
}

See a demo

Upvotes: 1

prog-fh
prog-fh

Reputation: 16925

x.mf is not a type but a member-function pointer. We must pass it as a parameter.

Here is your modified example (not certain about what you want to do).

#include <iostream>

struct S
{
    int i=123;

    void mf () { std::cout << "i=" << i << '\n'; };

    template <typename f>
    void func (f fnct)
    {
        (this->*fnct)();   
    }
};

int main()
{
    S x{456};
    
    x.func(&S::mf);
}

Upvotes: 1

AndyG
AndyG

Reputation: 41100

Calling member functions through a pointer can be so tricky.

You want to pass a member function pointer to S::mf like so:

struct S
{
    void mf () {std::cout << "called mf\n";};

    template <auto f>
    void func ()
    {
        (this->*f)(); 
    }
};

int main()
{
    S x;
    x.func<&S::mf>();
}

Upvotes: 3

Related Questions