I try to write a generic member Delegate
function (based on this cool answer generic member function pointer as a template parameter):
template <typename T, T>
class Delegate {};
template <typename T, typename R, typename... Args, R (T::*TMember)(Args...)>
class Delegate<R (T::*)(Args...), TMember> {
public:
Delegate(T &obj) : obj_{obj} {}
R operator()(Args &&... args) const noexcept(
noexcept((obj_.*TMember)(std::forward<Args>(args)...))) {
return (obj_.*TMember)(std::forward<Args>(args)...);
}
private:
T &obj_;
};
template <typename T, typename R, typename... Args, R (T::*TMember)(Args...) const>
class Delegate<R (T::*)(Args...) const, TMember> {
public:
Delegate(const T &obj) : obj_{obj} {}
R operator()(Args &&... args) const noexcept(
noexcept((obj_.*TMember)(std::forward<Args>(args)...))) {
return (obj_.*TMember)(std::forward<Args>(args)...);
}
private:
const T &obj_;
};
struct Foo {
int Bar(int a, int b) noexcept { return a + b; }
int ConstBar(int a, int b) const noexcept { return a + b; }
};
int main() {
Foo obj;
auto add = Delegate<int (Foo::*)(int, int), &Foo::Bar>(obj);
std::cout << add(1, 2) << std::endl; // 3
const Foo const_obj;
auto const_add =
Delegate<int (Foo::*)(int, int) const, &Foo::ConstBar>(const_obj);
std::cout << const_add(3, 4) << std::endl; // 7
return 0;
}
So, the questions are:
- Can i somehow omit fuzzy pointer to member in
Delegate
instantiation, like this:Delegate<Foo::Bar>(obj)
? - I'm lazy, and specifying member signature two times looks too hard for me. Can we somehow deduce template signature based on single template argument, so
Delegate<int (Foo::*)(int, int), &Foo::Bar>(obj)
becomesDelegate<&Foo::Bar>(obj)
? - To write generic code i need to propagate
noexcept
specifier from member toDelegate
'soperator()
vianoexcept(noexcept((obj_.*TMember)(std::forward<Args>(args)...)))
. Maynoexcept
specifier be derived fromreturn
body itself, instead of specifying body both times? - I need to specialize both versions -
const
and non-const
ones. May compiler do this for me? What aboutvolatile
/const volatile
specializations, should i copy the same code again and again?
If smth is impossible, please, describe why, or, at least, where can i read about :)