我想创建一个类,而不是在实例化时接受一个可变数量的函数参考,而这些函数参考已事先已知。这是一个几乎可以做我想要的例子:
// To show the function refs being used
void p(int arg) { cout << "int " << arg << endl; }
void p(string arg) { cout << "string " << arg << endl; }
void p(int arg1, int arg2) { cout<<"int/int "<<arg1<<arg2<<endl; }
void p(int arg1, string arg2) { cout<<"int/string "<<arg1<<arg2<<endl; }
class foo {
public:
// CTOR takes variadic function refs
template <typename... Args>
foo(Args... args) { p(args()...); }
// "args()..." requires supplied functions to take no parameters
// but makes no requirement on their return values.
};
// Using lambdas, but free functions, std::bind(), etc. work too
foo i([]{return 1;}); // prints "int 1"
foo s([]{return string("one");}); // prints "string one"
foo b([]{return 2;},
[]{return string("two");}); // prints "int/string 2two"
我看不到如何解决此问题,以便在构造函数中未评估作为参数的函数。我希望通过foo
中的另一种方法稍后拨打p(args()...)
。这就是为什么不能简单地创建foo作为 foo i(1)
的原因:稍后需要调用参数函数,而多次,不仅仅是创建对象时一次(它们比返回一个更复杂常数)。
问题似乎归结为保存对构造函数参数的引用,而当类不知道这些参数将具有多少签名或哪些签名时。某种程度上,这些论点需要成为类模板的一部分,而不仅仅是构造函数模板,但是如何?
如果传递的功能都具有相同的签名,则可以使用具有非类型参数的类模板并作为模板参数提供函数:
template <int (&...Arg)()>
class bar {
public:
bar() { p(Arg()...); }
other() { p(Arg()...); } // Use in any method
};
int one() { return 1; }
int two() { return 2; }
bar<one> bi; // Prints "int 1"
bar<one, two> bii; // Prints "int/int 12"
,但这需要所有参数是返回int且不能与lambdas一起使用的函数,因为它们不能为模板参数。
您可以使用lambda和 std::function
做到这一点。
请注意,lambda可以捕获一个参数包,然后(我说)稍后将其解开。
它遵循一个最小的工作示例:
#include<iostream>
#include<functional>
void p(int arg) { std::cout << "int " << arg << std::endl; }
void p(std::string arg) { std::cout << "string " << arg << std::endl; }
void p(int arg1, int arg2) { std::cout<<"int/int "<<arg1<<arg2<<std::endl; }
void p(int arg1, std::string arg2) { std::cout<<"int/string "<<arg1<<arg2<<std::endl; }
class foo {
public:
template <typename... Args>
foo(Args... args): func{[args...](){ p(args()...); }} {}
void operator()() { func(); }
private:
std::function<void()> func;
};
int main() {
// create your objects...
foo i([]{return 1;});
foo s([]{return std::string("one");});
foo b([]{return 2;}, []{return std::string("two");});
// ... and use them later
i();
s();
b();
}