问题描述
我想实现一个通用函数,该函数将引用对象及其成员函数的指针并调用它。但是,当我的类同时具有const和非const方法时,由于我需要提供两个重载,我无法这样做:
template<typename Ret,typename Class,typename ...Us>
Ret callMethod(Class &object,Ret (Class::*method)(Us...))
{
return (object.*method)(Us{}...);
}
template<typename Ret,Ret (Class::*method)(Us...) const)
{
return (object.*method)(Us{}...);
}
有没有办法只编写1个同时接受const和非const方法指针的模板函数,这样我就不必编写两次代码了?我正在使用C ++ 14。
从更广泛的角度来看,我最终要实现的是传递第3个参数,这是一个数据缓冲区,将从该缓冲区中提取方法参数-因此,模板函数将尽可能通用地处理它。
解决方法
简短的答案是,不要自己实现,它已经以std::invoke
的形式为您完成:
#include <functional>
struct A {
void foo(int x);
void bar(int x) const;
};
void example() {
A a;
std::invoke(&A::foo,a,3);
std::invoke(&A::bar,3);
}
回顾一下,您已经添加了C ++ 14标记,std::invoke
的文档提供了一个示例实现,可以在您的项目中使用。
这是不使用std::function
的C ++ 14替代方法。
我最终要实现的是传递第3个参数,这是一个数据缓冲区,将从该缓冲区中提取方法参数-因此,模板函数将尽可能通用地处理它
您在呼叫站点使用的内容将在此处完美转发:
template<typename Class,typename Func,typename... Args>
decltype(auto) callMethod_impl(Class& object,Func method,Args&&... args) {
return (object.*method)(std::forward<Args>(args)...);
}
template<typename Ret,typename Class,typename... Us,typename... Args>
Ret callMethod(Class& object,Ret(Class::*method)(Us...),Args&&... args) {
return callMethod_impl(object,method,std::forward<Args>(args)...);
}
template<typename Ret,typename... Args>
Ret callMethod(const Class& object,Ret(Class::*method)(Us...) const,std::forward<Args>(args)...);
}
如果在Ret
中需要callMethod_impl
,只需将其添加为模板参数,然后从callMethod_impl<Ret>(...)
重载(Demo)中调用callMethod
即可。
如果没有std::invoke
,则只能基于类型擦除来或多或少地采用一些通用的解决方法。使用std::function
可以创建代理功能,以平等对待您的功能:
#include <iostream>
#include <functional>
template<typename Ret,typename ...Us>
Ret callMethod_impl(std::function<Ret(Us...)> f) {
// common implementation here
return f(Us{}...);
}
template<typename Ret,typename ...Us>
Ret callMethod(Class &object,Ret (Class::*method)(Us...)) {
return callMethod_impl(std::function<Ret(Us...)>(std::bind(method,object)));
}
template<typename Ret,typename ...Us>
Ret callMethod(const Class &object,Ret (Class::*method)(Us...) const) {
return callMethod_impl(std::function<Ret(Us...)>(std::bind(method,object)));
}
struct Foo {
int bar() const { return 1; }
float bar() { return 2.1f; };
};
int main() {
Foo f;
std::cout << callMethod(f,&Foo::bar) << std::endl;
}
请注意,此处没有处理volatile
函数(+组合),但是也许您不需要完全的通用性,而是务实的解决方案。