Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can this member function selection code be written without std::invoke?

I was trying to select a member fn based on some constexpr value. I then tried to call the selected function, but I was getting errors about how I am calling member fn with incorrect syntax.

error: must use '.*' or '->*' to call pointer-to-member function in
'S::SelectedGetter<&S::fn1, &S::fn2>::fn (...)', e.g. '(... ->*
S::SelectedGetter<&S::fn1, &S::fn2>::fn) (...)'     
    18 |     return SelectedGetter<&S::fn1, &S::fn2>::fn();

I tried to call it "properly" but failed. In the end I am using std::invoke, but I wonder if this can be done without std::invoke, using just "raw" C++ syntax.

#include <algorithm>
#include <type_traits>

static constexpr int number = 18;

struct S
{
    using GetterFn = uint32_t(S::*)() const;
    uint32_t fn1()const {
        return 47;
    }
    uint32_t fn2() const {
        return 8472;
    }

    template <GetterFn Getter1, GetterFn Getter2>
    struct SelectedGetter
    {
        static constexpr GetterFn fn = (number < 11) ? Getter1 : Getter2;
    };

    uint32_t f() {
        return std::invoke((SelectedGetter<&S::fn1, &S::fn2>::fn), this);
    }
};

int main() 
{
    return S{}.f() % 100;
}

godbolt link

Note: I am fine with C++20 solutions, for example if some concepts magic can help...

like image 968
NoSenseEtAl Avatar asked Aug 21 '20 11:08

NoSenseEtAl


People also ask

What is the purpose of std :: Invoke?

The std::invoke function in the C++ standard library is usually used to call a functor with parameters. std::function<void(int)> func = ...; // same as func(42) std::invoke(func, 42);

What is STD invoke?

std::invoke( f, args... ) is a slight generalization of typing f(args...) that also handles a few additional cases. Something callable includes a function pointer or reference, a member function pointer, an object with an operator() , or a pointer to member data.

Can we call member function using this pointer?

You can use pointers to member functions in the same manner as pointers to functions. You can compare pointers to member functions, assign values to them, and use them to call member functions.

Can we call member function using this pointer from constructor?

the constructor is the first function which get called. and we can access the this pointer via constructor for the first time. if we are able to get the this pointer before constructor call (may be via malloc which will not call constructor at all), we can call member function even before constructor call.


1 Answers

You can call it like normal member function pointer call. The correct syntax would be

 return ((*this).*SelectedGetter<&S::fn1, &S::fn2>::fn)();

or

return (this->*SelectedGetter<&S::fn1, &S::fn2>::fn)();

(See a demo)


Side notes:

  • If the functions you call in f are const, also you could make it also uint32_t f() const
  • Secondly, you can replace the SelectedGetter with a variable template (since c++14), and now you need less-typing

It will look like

// variable template
template<GetterFn Getter1, GetterFn Getter2>
static constexpr auto fn = (number < 11) ? Getter1 : Getter2;

uint32_t f() const {
   return (this->*fn<&S::fn1, &S::fn2>)();
}

(See a demo)

like image 63
JeJo Avatar answered Sep 20 '22 09:09

JeJo