使用成员函数调用可变参数模板函数

时间:2017-07-27 15:40:05

标签: c++ templates variadic-templates

根据我之前的问题Variadic template, function as argument

我最终得到了一个简单的类,但是如何使用std :: invoke或其他方法调用Tester :: test作为参数? http://en.cppreference.com/w/cpp/utility/functional/invoke#Example提供的示例对我没有多大帮助,我尝试了很多不同的方法来使用std :: invoke。

class Tester {
public:
    template<typename F, typename... Args>
    decltype(auto) test(F&& f, Args&&... args) {
        return std::forward<F>(f)(std::forward<Args>(args)...);
    }
    int simple(int i) { return i; }
};

int main()
{
    Tester t;
    std::cout << t.test(t.simple, 3); // how do you modify this line such that the code compiles?
}

谢谢!

3 个答案:

答案 0 :(得分:5)

一种方法是修改class Tester { public: template<typename F, typename... Args> decltype(auto) test(F&& f, Args&&... args) { return std::invoke(std::forward<F>(f), std::forward<Args>(args)...); } int simple(int i) { return i; } }; 成员函数的定义,如下所示:

test()

然后我们可以将一个成员函数指针传递给int main() { Tester t; std::cout << t.test(&Tester::simple, t, 3); } ,其中应该调用该方法的实例作为第二个参数,然后是函数参数本身:

std::invoke

这可行的原因是因为std::invoke(ptr-to-member, instance, args...); 有一个special overload for pointers-to-members,所以

(instance.*ptr-to-member)(args...);

被称为

s3

这正是我们在这种情况下想要的。

答案 1 :(得分:3)

注意,std::invoke C ++ 17 的一部分。如果它不可用,可以实现test函数,以便它接受指向成员函数的指针和类的实例:

template<typename F, typename T, typename... Args>
decltype(auto) test(F f, T&& t, Args&&... args) {
    return (std::forward<T>(t).*f)(std::forward<Args>(args)...);
}

现在test接受一个指向成员函数的指针作为第一个参数,一个类的实例作为第二个参数和任意数量的附加参数。

然后test可能被称为:

Tester t;
std::cout << t.test(&Tester::simple, t, 42);

WANDBOX EXAMPLE

答案 2 :(得分:1)

再提一个可能性,你可以将成员函数调用包装在lambda中并捕获实例t。在C ++ 14中,我们可以使用通用lambda,因此我们不必明确指定参数。

#include <iostream>
#include <utility>

class Tester {
public:
    template<typename F, typename... Args>
    decltype(auto) test(F&& f, Args&&... args) {
        return std::forward<F>(f)(std::forward<Args>(args)...);
    }
    int simple(int i) { return i; }
};

int main()
{
    Tester t;
    std::cout << t.test([&t] (auto&&... args) { return t.simple(std::forward<decltype(args)>(args)...); }, 3);
}