C++11 可变参数模板在 class 中调用函数
C++11 variadic templates calling a function inside a class
我正在学习 C++11 中的可变参数模板。如何调用 test.finder
作为 test.var_finder
的函数参数?
#include <functional>
#include <iostream>
class c_test {
public:
double finder(double a, double b = 0) {
return a + b;
};
template<typename... Args>
double var_finder(double c, Args... args, std::function<double (Args... args)> func) {
return c * func(args...);
};
};
int main () {
c_test test;
std::cout << test.var_finder(0.1, 2, test.finder) << std::endl;
return 0;
}
我的预期结果是 0.1 * (2 + 0) = 0.2。
这里有很多事情要处理。
首先,把参数包args
放在最后,否则编译器不知道在哪里停止匹配参数(除非你指定模板参数)。
template<typename... Args>
double var_finder(double c, std::function<double (Args... args)> func, Args... args)
其次,不要在std::function
中命名参数;也不要使用 std::function
,而是使用函数指针。
template<typename... Args>
double var_finder(double c, double (*func)(Args...), Args... args)
第三,使 finder
静态,否则你 运行 成成员函数指针,语法更难掌握(稍后详细介绍)。
static double finder(double a, double b = 0)
第三,为 finder
提供可选参数。否则无法推导出参数包,因为它不匹配 func
和 args
.
std::cout << test.var_finder(0.1, c_test::finder, 2.0, 0.0) << std::endl;
这为您提供了以下信息。
class c_test {
public:
static double finder(double a, double b = 0) {
return a + b;
}
template<typename... Args>
double var_finder(double c, double (*func)(Args...), Args... args) {
return c * func(args...);
}
};
int main () {
c_test test;
std::cout << test.var_finder(0.1, c_test::finder, 2.0, 0.0) << std::endl;
}
如果你真的需要finder
不是静态的,那么你必须处理成员函数指针语法。
首先参数func
必须是成员函数指针
double (c_test::*func)(Args...) // parameter declaration
&c_test::finder // argument in call
然后,您需要将 c_test
变量传递给 var_finder
才能调用 func
。
template<typename... Args>
double var_finder(double c, double (c_test::*func)(Args...), c_test test, Args... args) {
return c * (test.*func)(args...);
}
// [...]
std::cout << test.var_finder(0.1, &c_test::finder, test, 2.0, 0.0) << std::endl;
这将为您提供以下代码。
class c_test {
public:
double finder(double a, double b = 0) {
return a + b;
}
template<typename... Args>
double var_finder(double c, double (c_test::*func)(Args...), c_test test, Args... args) {
return c * (test.*func)(args...);
}
};
int main () {
c_test test;
std::cout << test.var_finder(0.1, &c_test::finder, test, 2.0, 0.0) << std::endl;
}
如果您希望能够在不指定可选参数的情况下调用 finder
,那么您需要一些中介,例如 lambda。
你的解决方案有很多问题:
1) 不能将成员函数转换为 std::function
,因为没有对象就永远无法调用成员函数。您可以通过使成员函数 static
或使用 std::bind
或使用 lambda 来解决此问题。
2) 方法参数中间不能有可变参数列表。可变参数必须到达参数列表的末尾。
3) 您不能在参数列表本身中推导模板参数 "on the fly"。解决方案:使用带有默认模板参数的新模板参数。
4) 我认为没有机会为我们想要在 std::function 中使用的函数设置默认参数,并产生不同的签名 double(double)
与 double(double,double)
class c_test {
public:
static double finders(double a, double b = 0) {
return a + b;
};
double finder(double a, double b = 0) {
return a + b;
};
template<typename... Args, typename F= std::function<double(Args...)> >
double var_finder(double c, F func, Args... args) {
return c * func(args...);
}
};
int main () {
c_test test;
// use static member
std::cout << test.var_finder(0.1, test.finders, 2.,3.) << std::endl;
// use lambda instead of all the hacky things
std::cout << test.var_finder(0.1, [&test](double p1,double p2){ return test.finder(p1,p2); }, 2.,3.) << std::endl;
return 0;
}
您可以简单地这样做:
class c_test
{
public:
double finder(double a, double b = 0)
{
return a + b;
};
template<typename Func, typename... Args>
double var_finder(double c, Func func, Args... args)
{
return c * func(args...);
};
};
int main()
{
c_test test;
auto f_1 = std::bind(std::mem_fn(&c_test::finder), test, std::placeholders::_1, 0);
auto f_2 = std::bind(std::mem_fn(&c_test::finder), test, std::placeholders::_1, std::placeholders::_2);
std::cout << test.var_finder(0.1, f_1, 2.0) << std::endl;
std::cout << test.var_finder(0.1, f_2, 2.0, 3.0) << std::endl;
return 0;
}
结果是:
0.2
0.5
我猜你有点把可变参数模板部分和一些设计缺陷混在一起了
开始吧。
Preamble:可变参数模板的正确处理方式是使用rvalue-reference
和std::forward
实现perfect forwarding.
1) 简单的方法:你根本不需要class
您实际上并没有指代任何成员,因此 class 只会带来复杂性。这些情况最好参考一个免费的函数
#include <functional>
#include <iostream>
double finder(double a, double b = 0) {
return a + b;
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};
int main () {
std::cout << var_finder(0.1, finder, 2, 0) << std::endl;
return 0;
}
您的函数接受 2 个参数,因此您必须将零作为第二个参数传递。
2) 使用 class
你尝试的问题是你想用 c_test
本身的函数调用 c_test.var_finder
。现在你必须弄清楚你想要什么样的设计。你可以做出2个假设。首先是 "I want anyway a finder function inside my class",然后你必须使它成为 static
因为它真的不使用 class 成员所以你不需要 c_test
的实例,对吗?所以使用自由函数或静态成员函数会留下 var_finder
实现,你只需要这样调用它
#include <functional>
#include <iostream>
class c_test {
public:
static double finder(double a, double b = 0) {
return a + b;
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};
};
int main () {
c_test test;
std::cout << test.var_finder(0.1, &c_test::finder, 2, 0) << std::endl;
return 0;
}
您可以做的第二个假设是"nope, I want any function member to be called with var_finder regardless where it comes from"。我强烈反对这种方法,因为它是从糟糕的设计中提取解决方案,所以我建议重新考虑您的设计以落入解决方案 1 或 2。
3) 奖励:设计不错
您可以添加一个非可变参数函数并将用法委托给 lambda 的使用,这允许您在其中使用一个成员函数而无需定义可变参数模板来处理它(这是常见的实现对于 std 库函数)。
#include <functional>
#include <iostream>
double finder(double a, double b = 0) {
return a + b;
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f) {
return c * std::forward<Func>(f)();
};
class c_test
{
public:
double finder(double a, double b = 0) {
return a + b;
};
};
int main () {
double a = 2.0;
double b = 0.0;
// use as usual
std::cout << var_finder(0.1, finder, a, b) << std::endl;
// use with lambda
std::cout << var_finder(0.1, [a,b](){ return a+b; }) << std::endl;
// lambda with member argument, less gruesome than a variadic template calling a member function
c_test c;
std::cout << var_finder(0.1, [a,b, &c](){ return c.finder(a,b); }) << std::endl;
return 0;
}
我正在学习 C++11 中的可变参数模板。如何调用 test.finder
作为 test.var_finder
的函数参数?
#include <functional>
#include <iostream>
class c_test {
public:
double finder(double a, double b = 0) {
return a + b;
};
template<typename... Args>
double var_finder(double c, Args... args, std::function<double (Args... args)> func) {
return c * func(args...);
};
};
int main () {
c_test test;
std::cout << test.var_finder(0.1, 2, test.finder) << std::endl;
return 0;
}
我的预期结果是 0.1 * (2 + 0) = 0.2。
这里有很多事情要处理。
首先,把参数包args
放在最后,否则编译器不知道在哪里停止匹配参数(除非你指定模板参数)。
template<typename... Args>
double var_finder(double c, std::function<double (Args... args)> func, Args... args)
其次,不要在std::function
中命名参数;也不要使用 std::function
,而是使用函数指针。
template<typename... Args>
double var_finder(double c, double (*func)(Args...), Args... args)
第三,使 finder
静态,否则你 运行 成成员函数指针,语法更难掌握(稍后详细介绍)。
static double finder(double a, double b = 0)
第三,为 finder
提供可选参数。否则无法推导出参数包,因为它不匹配 func
和 args
.
std::cout << test.var_finder(0.1, c_test::finder, 2.0, 0.0) << std::endl;
这为您提供了以下信息。
class c_test {
public:
static double finder(double a, double b = 0) {
return a + b;
}
template<typename... Args>
double var_finder(double c, double (*func)(Args...), Args... args) {
return c * func(args...);
}
};
int main () {
c_test test;
std::cout << test.var_finder(0.1, c_test::finder, 2.0, 0.0) << std::endl;
}
如果你真的需要finder
不是静态的,那么你必须处理成员函数指针语法。
首先参数func
必须是成员函数指针
double (c_test::*func)(Args...) // parameter declaration
&c_test::finder // argument in call
然后,您需要将 c_test
变量传递给 var_finder
才能调用 func
。
template<typename... Args>
double var_finder(double c, double (c_test::*func)(Args...), c_test test, Args... args) {
return c * (test.*func)(args...);
}
// [...]
std::cout << test.var_finder(0.1, &c_test::finder, test, 2.0, 0.0) << std::endl;
这将为您提供以下代码。
class c_test {
public:
double finder(double a, double b = 0) {
return a + b;
}
template<typename... Args>
double var_finder(double c, double (c_test::*func)(Args...), c_test test, Args... args) {
return c * (test.*func)(args...);
}
};
int main () {
c_test test;
std::cout << test.var_finder(0.1, &c_test::finder, test, 2.0, 0.0) << std::endl;
}
如果您希望能够在不指定可选参数的情况下调用 finder
,那么您需要一些中介,例如 lambda。
你的解决方案有很多问题:
1) 不能将成员函数转换为 std::function
,因为没有对象就永远无法调用成员函数。您可以通过使成员函数 static
或使用 std::bind
或使用 lambda 来解决此问题。
2) 方法参数中间不能有可变参数列表。可变参数必须到达参数列表的末尾。
3) 您不能在参数列表本身中推导模板参数 "on the fly"。解决方案:使用带有默认模板参数的新模板参数。
4) 我认为没有机会为我们想要在 std::function 中使用的函数设置默认参数,并产生不同的签名 double(double)
与 double(double,double)
class c_test {
public:
static double finders(double a, double b = 0) {
return a + b;
};
double finder(double a, double b = 0) {
return a + b;
};
template<typename... Args, typename F= std::function<double(Args...)> >
double var_finder(double c, F func, Args... args) {
return c * func(args...);
}
};
int main () {
c_test test;
// use static member
std::cout << test.var_finder(0.1, test.finders, 2.,3.) << std::endl;
// use lambda instead of all the hacky things
std::cout << test.var_finder(0.1, [&test](double p1,double p2){ return test.finder(p1,p2); }, 2.,3.) << std::endl;
return 0;
}
您可以简单地这样做:
class c_test
{
public:
double finder(double a, double b = 0)
{
return a + b;
};
template<typename Func, typename... Args>
double var_finder(double c, Func func, Args... args)
{
return c * func(args...);
};
};
int main()
{
c_test test;
auto f_1 = std::bind(std::mem_fn(&c_test::finder), test, std::placeholders::_1, 0);
auto f_2 = std::bind(std::mem_fn(&c_test::finder), test, std::placeholders::_1, std::placeholders::_2);
std::cout << test.var_finder(0.1, f_1, 2.0) << std::endl;
std::cout << test.var_finder(0.1, f_2, 2.0, 3.0) << std::endl;
return 0;
}
结果是:
0.2
0.5
我猜你有点把可变参数模板部分和一些设计缺陷混在一起了
开始吧。
Preamble:可变参数模板的正确处理方式是使用rvalue-reference
和std::forward
实现perfect forwarding.
1) 简单的方法:你根本不需要class
您实际上并没有指代任何成员,因此 class 只会带来复杂性。这些情况最好参考一个免费的函数
#include <functional>
#include <iostream>
double finder(double a, double b = 0) {
return a + b;
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};
int main () {
std::cout << var_finder(0.1, finder, 2, 0) << std::endl;
return 0;
}
您的函数接受 2 个参数,因此您必须将零作为第二个参数传递。
2) 使用 class
你尝试的问题是你想用 c_test
本身的函数调用 c_test.var_finder
。现在你必须弄清楚你想要什么样的设计。你可以做出2个假设。首先是 "I want anyway a finder function inside my class",然后你必须使它成为 static
因为它真的不使用 class 成员所以你不需要 c_test
的实例,对吗?所以使用自由函数或静态成员函数会留下 var_finder
实现,你只需要这样调用它
#include <functional>
#include <iostream>
class c_test {
public:
static double finder(double a, double b = 0) {
return a + b;
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};
};
int main () {
c_test test;
std::cout << test.var_finder(0.1, &c_test::finder, 2, 0) << std::endl;
return 0;
}
您可以做的第二个假设是"nope, I want any function member to be called with var_finder regardless where it comes from"。我强烈反对这种方法,因为它是从糟糕的设计中提取解决方案,所以我建议重新考虑您的设计以落入解决方案 1 或 2。
3) 奖励:设计不错
您可以添加一个非可变参数函数并将用法委托给 lambda 的使用,这允许您在其中使用一个成员函数而无需定义可变参数模板来处理它(这是常见的实现对于 std 库函数)。
#include <functional>
#include <iostream>
double finder(double a, double b = 0) {
return a + b;
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f) {
return c * std::forward<Func>(f)();
};
class c_test
{
public:
double finder(double a, double b = 0) {
return a + b;
};
};
int main () {
double a = 2.0;
double b = 0.0;
// use as usual
std::cout << var_finder(0.1, finder, a, b) << std::endl;
// use with lambda
std::cout << var_finder(0.1, [a,b](){ return a+b; }) << std::endl;
// lambda with member argument, less gruesome than a variadic template calling a member function
c_test c;
std::cout << var_finder(0.1, [a,b, &c](){ return c.finder(a,b); }) << std::endl;
return 0;
}