Это досадно трудная проблема, которая постоянно приводит к предложениям по языку в попытке ее решить ( P0119 , P0834 , P1170 ).
До этого вопрос о том, как обернуть вызов определенной функции-члена для типа, где эта функция-член либо перегружена, либо является шаблоном или принимает аргументы по умолчанию, является довольно сложным.
Самый простой способ сделать это - написать лямбду:
[](A& a, auto&&... args) -> decltype(a.show(FWD(args)...)) { return a.show(FWD(args)...); }
Но на самом деле это не так просто и не особенно удобно - и это действительно только в случае, когда show
вызывается для не const
A
. Что если бы у нас были перегрузки const
и не const
? Или &
и &&
?
Самый полный способ реализовать это, на мой взгляд, это использовать Boost.HOF с этим макросом :
#define CLASS_MEMBER(T, mem) boost::hof::fix(boost::hof::first_of(\
boost::hof::match( \
[](auto, T& s, auto&&... args) \
BOOST_HOF_RETURNS(s.mem(FWD(args)...)), \
[](auto, T&& s, auto&&... args) \
BOOST_HOF_RETURNS(std::move(s).mem(FWD(args)...)), \
[](auto, T const&& s, auto&&... args) \
BOOST_HOF_RETURNS(std::move(s).mem(FWD(args)...)), \
[](auto, T const& s, auto&&... args) \
BOOST_HOF_RETURNS(s.mem(FWD(args)...))), \
[](auto self, auto&& this_, auto&&... args) \
BOOST_HOF_RETURNS(self(*FWD(this_), FWD(args)...)) \
))
который в вашем случае вы хотите: CLASS_MEMBER(A, show)
. Это даст вам функциональный объект, который вы можете правильно вызывать:
auto show_fn = CLASS_MEMBER(A, show);
show_fn(a, 1); // ok, calls a.show(1)
show_fn(a, 1, 2); // ok, calls a.show(1, 2)
show_fn(a, 1, 2, 3); // error, no matching call - but sfinae friendly