[英]Pass overloaded member function to a variadic template function
我有一个带有函数add的类:
class Pool {
public:
Pool() {};
template<class F, class... A>
auto add(F&& f, A&&... args) -> std::future<typename std::result_of<F(A...)>::type>
{
// return empty placeholder, for the sake of this code example
std::future<typename std::result_of<F(A...)>::type> ret;
return ret;
};
};
它应该使用带有参数的任何函数,将其添加到线程池中,并返回该函数的结果类型的后继。
还有一个我使用它的类:
class MyClass {
public:
string doIt(string) { return string("a"); };
string doIt(int, string) { return string("b"); };
void test() {
Pool myPool;
string a("test");
myPool.add(&MyClass::doIt, a); // Error
};
};
这会导致编译器错误:
Error 1 error C2914: 'Pool::add' : cannot deduce template argument as function argument is ambiguous MyClass.cpp 94
现在的问题是(我认为)编译器无法推断出我想使用哪个重载。 类似于重载函数作为可变参数模板函数的参数 。 (我也不是100%清楚为什么我必须对类成员函数使用“&”,但是如果我传入一个自由函数,就不会使用&号)。 无论如何,我也尝试了以上答案中提到的解决方法:
struct doIt_wrapper {
template <typename... T>
auto operator()(T... args) -> decltype(doIt(args...)) {
return doIt(args...);
}
};
然后将MyClass :: test()修改为:
void test() {
Pool myPool;
string a("test");
myPool.add(doIt_wrapper(), a);
};
但这也给了我一个编译器错误:
error C2893: Failed to specialize function template 'unknown-type doIt_wrapper::operator ()(T...)' C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xrefwrap 58
我还尝试了一些变体,例如myPool.add(doIt_wrapper<string>()
并且带有/不带有“&”,但它们都会生成一个或另一个编译器错误。
我想我还没有完全理解这个问题,如果有人能对此问题有所了解,我会感到很高兴。 另外,我也在寻找解决此问题的适当方法。 只要没有两个具有相同名称的函数,就不可能真正做到这一点,并且一旦存在,没有适当的通用解决方案,一切都会崩溃吗?
编辑:修正了一些拼写错误,并在此处上传了一个最小示例: http : //ideone.com/eX1r1l
正如其他人提到的那样,问题在于doIt()
在doIt_wrapper
类内部不可调用,因为它还需要一个指向所调用对象的指针。 你可以只修改doIt_wrapper
operator()
也采取一个指向对象的指针和一个指针传递给this
作为第一个参数add()
然后看起来像这样:
#include <iostream>
#include <future>
using namespace std;
class Pool {
public:
Pool() {};
template<class F, class... A>
auto add(F&& f, A&&... args) -> std::future<typename std::result_of<F&&(A&&...)>::type>
{
// return empty placeholder, for the sake of this code example
std::future<typename std::result_of<F&&(A&&...)>::type> ret;
return ret;
};
};
class MyClass {
public:
string doIt(string) { return string("a"); };
string doIt(int, string) { return string("b"); };
struct doIt_wrapper
{
template<class T, class... Ts>
auto operator()(T&& t, Ts&&... args) -> decltype(t->doIt(std::forward<Ts>(args)...))
{
return t->doIt(std::forward<Ts>(args)...);
}
};
void test() {
Pool myPool;
string a("test");
myPool.add(doIt_wrapper(), this, a); // No error no more
};
};
int main() {
// your code goes here
MyClass my;
my.test();
return 0;
}
这样,您就不必进行强制转换。 该代码可在GCC和Clang上编译。
您可以使用lambda:
myPool.add([this](const std::string& s) {doIt(s);}, a);
甚至
myPool.add([this, a]() {doIt(a);});
当前,您可以指示要使用哪种重载方式:
myPool.add(static_cast<std::string (MyClass::*) (std::string)>(&MyClass::doIt), a);
请注意, doIt
是一种方法(不是自由函数或静态函数),因此您必须使用一个对象来调用它。 如果在doIt
添加static
,则可以选择重载
myPool.add(static_cast<std::string (*) (std::string)>(&MyClass::doIt), a);
问题在于非静态成员函数具有隐藏的,隐式的this
参数, this
参数指向调用它的实例。 您的编译器拒绝它是正确的,因为它没有该函数的正确参数。 发送this
作为附加的绑定参数将起作用:
myPool.add(&MyClass::doIt, this, a);
// ^^^^
使用lamda表达式也可以。
此外,标准库函数std::async()
已经完成了您在此尝试做的事情,甚至更多。 考虑改用它。
编辑:您还需要强制转换为正确的类型以选择正确的重载。 @ Jarod42已经向您展示了如何。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.