将重载的成员函数传递给函数模板
Passing an overloaded member function to function template
我想要一个函数,它用提供的可变输入参数调用给定的成员函数。我写了这样的东西:
#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
签名完全匹配,包括可能的cv和ref限定符。
相关文章:
- 如何在c++中为模板函数实例创建快捷方式
- 当函数模板参数是具有默认参数的类模板时,函数模板参数的推导如何执行
- 如何使用模板函数的函数签名进行SFINAE
- C++浮点数据类型和字符串数据类型无法子到模板函数中
- 将重载的成员函数传递给函数模板
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 在一个模板函数中,若输入的类型是enum类,我该如何使用std::underlying_type
- 实现一个在集合上迭代的模板函数
- C++17中函数模板中的静态数组初始化(MSVC 2019)
- 模板函数指针和lambda
- 特征:模板函数中矩阵的平面图
- 一位朋友将模板函数缩写为clang和gcc
- 模板函数调用
- C++模板函数,用于比较任何无符号整数和有符号整数
- 具有多个模板的模板函数,用于特定数据类型(如字符串)?
- 为什么 gcc 和 clang 为函数模板的实例化生成不同的符号名称?
- 如何制作指向模板函数的指针?
- 字符串化递归的"std::vector<std::vector<...>>"而不使用部分模板函数专用化
- 尝试根据类中 typedef 的存在来专门化模板函数
- 检测传递给函数模板函数参数的特定函数