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

Calling a variadic template function with a member function

本文关键字:参数 函数 变参 成员 函数调用      更新时间:2023-10-16

基于我之前的问题 可变参数模板,函数作为参数

我最终在下面得到了一个简单的类,但是我如何使用 std::invoke 或其他一些方法来调用 Tester::test 与 Tester::simple 作为参数?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?
}

谢谢!

一种方法是修改test()成员函数的定义,如下所示:

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...);

被称为

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

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

请注意,std::invokeC++ 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);

魔杖盒示例

只是为了提及另一种可能性,您可以将成员函数调用包装在 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);
}