[英]Passing an overloaded member function to function template
我想有一个函数,它使用提供的variadic输入参数调用给定的成员函数。 我写了这样的东西:
#include <type_traits>
#include <utility>
struct A {
constexpr int show(int a, int b) const noexcept {return a + b;}
};
template <typename T, typename MemFn, typename ... Args>
int show(T && obj, MemFn Fn, Args&&... args)
{
return (obj.*Fn)(std::forward<Args>(args)...);
}
int main()
{
constexpr A a;
return show(a, &A::show, 1, 2);
}
并且它工作得很好,只要我的结构中只有一个show
方法的定义。 我一添加类似的东西
struct A {
constexpr int show(int a, int b) const noexcept {return a + b;}
constexpr int show(int a) const noexcept {return a * 3;}
};
编译器不能推断成员函数的类型,它确实有意义,但我想知道是否有解决这个问题的方法,比如在成员函数模板中嵌入输入参数类型或什么?
示例代码可以在这里找到。
这是一个令人讨厌的难题,它不断导致语言提案试图解决它( P0119 , P0834 , P1170 )。
在那之前,如何在类型上包装调用特定成员函数的问题是非常困难的,其中该成员函数被重载或者模板或者采用默认参数。
最简单的方法就是写一个lambda:
[](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
我想知道这个问题是否有解决方法,比如在成员函数模板中嵌入输入参数类型?
使用lambdas而不是对象和成员函数指针。 例如:
struct A {
constexpr int show(int a, int b) const noexcept {return a + b;}
constexpr int show(int a) const noexcept {return a * 3;}
};
template <typename F, typename ... Args>
int show(F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
int main() {
constexpr A a;
auto f = [&a](auto... args) { return a.show(std::forward<decltype(args)>(args)...); };
show(f, 1);
show(f, 1, 2);
}
您可以使用成员函数的更具体类型约束函数:
template <typename T, typename... Args>
int show(T && obj, int(std::remove_reference_t<T>::*Fn)(int, int) const, Args&&... args)
{
return (obj.*Fn)(std::forward<Args>(args)...);
}
但是,根据您的用例,此定义可能过于受限,因为现在Fn
参数必须与int(int, int) const
签名完全匹配int(int, int) const
包括可能的cv和ref-qualifiers。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.