我有一个功能添加:
的课程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
现在问题是(我认为)编译器无法推断出我想要使用哪个重载。与Overloaded function as argument of variadic template function相似。 (另外,我不是100%清楚为什么我必须使用“&amp;”作为类成员函数,但如果我传入一个免费函数则没有&符号)。 无论如何,我也尝试了上面回答中提到的解决方法:
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>()
和/不带'&amp;'但它们都会产生一个或另一个编译器错误。
我想我还没有完全理解这个问题,如果有人能够解释它,我会很高兴。此外,我正在寻找这个问题的正确解决方案。实际情况并非如此,只要没有两个具有相同名称的函数,这只会起作用,并且一旦有,一切都会在没有正确的通用解决方案的情况下崩溃吗?
编辑:修正了一些拼写错误,并在此处上传了一个最小示例:http://ideone.com/eX1r1l
答案 0 :(得分:2)
正如其他人所提到的,问题是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上编译。
答案 1 :(得分:1)
您可以使用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
是一种方法(不是自由函数或静态函数),因此您必须使用对象调用它。
如果您将static
添加到doIt
,则可以选择
myPool.add(static_cast<std::string (*) (std::string)>(&MyClass::doIt), a);
答案 2 :(得分:1)
问题是非静态成员函数有一个隐藏的隐式this
参数,该参数指向调用它的实例。您的编译器拒绝它是正确的,因为它没有正确的函数参数。发送this
作为附加绑定参数将起作用:
myPool.add(&MyClass::doIt, this, a);
// ^^^^
使用lamda表达式也可以。
此外,标准库函数std::async()
已经完成了您在此处尝试执行的操作,以及更多功能。请考虑使用它。
编辑:您还需要转换为正确的类型以选择正确的重载。 @Jarod42已经向您展示了如何。