繁体   English   中英

将重载成员函数传递给可变参数模板函数

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM