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;
}
Note: I am fine with C++20 solutions, for example if some concept
s magic can help...
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)();
Side notes:
f
are const
, also you could make it also uint32_t f() const
SelectedGetter
with a variable template (since c++14), and now you need less-typingIt 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>)();
}