有没有办法将具有任何类型和数量的参数的 void 函数作为参数传递给方法并将其存储在数据成员中? (C++)
Is there a way to pass a void function with any type and amount of arguments as an argument in a method and store it in a data member? (C++)
我 运行 在将函数作为参数传递到方法中时遇到问题。我的问题是我希望能够传递具有任何类型和数量的参数的任何 void 函数,然后将其存储在数据成员中。我目前所做的是对不带参数的 void 函数进行重载,并对具有 std::any 类型向量参数的 void 函数进行重载,然后为该向量添加一个额外的参数。这是我所做的一个例子:
typedef void (*FunctionT1)();
typedef void (*FunctionT2)(std::vector<std::any>);
class ExampleClass {
public:
void saveFunction(FunctionT1 f) {
emptyFunction = f;
}
void saveFunction(FunctionT2 f, std::vector<std::any> args) {
vectorFunction = f;
vectorFunctionArgs = args;
}
private:
FunctionT1 emptyFunction;
FunctionT2 vecotorFunction;
std::vector<std::any> vectorFunctionArgs;
}
现在这可行,我可以做我想做的事,但这显然是一个非常糟糕的解决方案。有没有办法以其他方式做到这一点? (我在考虑模板包,但无法弄清楚它们是如何工作的)
我想向您展示一个抽象工厂的例子。
对于工厂模式,我们通常会遇到问题,即所有构造函数都应该具有相同的签名。但是我们经常希望使用具有不同参数集的函数。
如果您查看下面的示例,我可以向工厂添加具有任意数量参数的函数。
我知道这不是您想要的,但它可能会提示您如何实现自己的功能。
#include <iostream>
#include <map>
#include <utility>
#include <any>
// Some demo classes ----------------------------------------------------------------------------------
struct Base {
Base(int d) : data(d) {};
virtual ~Base() { std::cout << "Destructor Base\n"; }
virtual void print() { std::cout << "Print Base\n"; }
int data{};
};
struct Child1 : public Base {
Child1(int d, std::string s) : Base(d) { std::cout << "Constructor Child1 " << d << " " << s << "\n"; }
virtual ~Child1() { std::cout << "Destructor Child1\n"; }
virtual void print() { std::cout << "Print Child1: " << data << "\n"; }
};
struct Child2 : public Base {
Child2(int d, char c, long l) : Base(d) { std::cout << "Constructor Child2 " << d << " " << c << " " << l << "\n"; }
virtual ~Child2() { std::cout << "Destructor Child2\n"; }
virtual void print() { std::cout << "Print Child2: " << data << "\n"; }
};
struct Child3 : public Base {
Child3(int d, long l, char c, std::string s) : Base(d) { std::cout << "Constructor Child3 " << d << " " << l << " " << c << " " << s << "\n"; }
virtual ~Child3() { std::cout << "Destructor Child3\n"; }
virtual void print() { std::cout << "Print Child3: " << data << "\n"; }
};
using UPTRB = std::unique_ptr<Base>;
template <class Child, typename ...Args>
UPTRB createClass(Args...args) { return std::make_unique<Child>(args...); }
// The Factory ----------------------------------------------------------------------------------------
template <class Key, class Object>
class Factory
{
std::map<Key, std::any> selector;
public:
Factory() : selector() {}
Factory(std::initializer_list<std::pair<const Key, std::any>> il) : selector(il) {}
template<typename Function>
void add(Key key, Function&& someFunction) { selector[key] = std::any(someFunction); };
template <typename ... Args>
Object create(Key key, Args ... args) {
if (selector.find(key) != selector.end()) {
return std::any_cast<std::add_pointer_t<Object(Args ...)>>(selector[key])(args...);
}
else return nullptr;
}
};
int main()
{
Factory<int, UPTRB> factory{
{1, createClass<Child1, int, std::string>},
{2, createClass<Child2, int, char, long>}
};
factory.add(3, createClass<Child3, int, long, char, std::string>);
// Some test values
std::string s1(" Hello1 "); std::string s3(" Hello3 ");
int i = 1; const int ci = 1; int& ri = i; const int& cri = i; int&& rri = 1;
UPTRB b1 = factory.create(1, 1, s1);
UPTRB b2 = factory.create(2, 2, '2', 2L);
UPTRB b3 = factory.create(3, 3, 3L, '3', s3);
b1->print();
b2->print();
b3->print();
b1 = factory.create(2, 4, '4', 4L);
b1->print();
return 0;
}
通过阅读问题和浏览评论,我认为这是最适合您的问题的,
#include <vector>
class ExampleClass {
public:
ExampleClass() = default;
/**
* Save a function pointer.
*
* @param Function: The function poitner.
* @return The index of the function.
*/
template<class Return = void, class... Args>
size_t SaveFunction(Return(*Function)(Args... args))
{
mFunctions.insert(mFunctions.end(), Function);
return mFunctions.size() - 1;
}
/**
* Call a saved function.
*
* @tparam Return: The return type of the function.
* @param index: The index of the function.
* @param args: The arguments the function requires.
* @return The return of the function.
*/
template<class Return = void, class... Args>
Return CallFunction(size_t index, const Args&... args)
{
typedef Return(*Function)(Args...);
return reinterpret_cast<Function>(mFunctions[index])(args...);
}
private:
std::vector<void*> mFunctions;
};
然后你就可以这样保存和调用任何函数了,
void Function() { std::cout << "Hello World\n"; }
void Add(int x, int y) { std::cout << x + y << std::endl; }
int main()
{
ExampleClass c;
size_t f1 = c.SaveFunction(Function);
size_t f2 = c.SaveFunction(Add);
c.CallFunction(f1);
c.CallFunction(f2, 1, 2);
}
这适用于具有任意数量参数的任何函数。
注意:如果 return 类型总是 void
,您可以将 Return
替换为 void
。
据我了解,您想调用一个函数 void()
,其中调用者可能会使用绑定参数注册其他函数类型。您可以使用 std::function
:
class ExampleClass {
public:
void saveFunction(std::function<void()> f) {
this->f = f;
}
void call() { f(); }
private:
std::function<void()> f;
};
有使用
void foo();
void bar(std::vector<std::any>);
std::vector<std::any> v;
ExampleClass ex;
ex.SaveFunction(&foo); ex.call(); // foo();
ex.SaveFunction([&]() { bar(v); }); ex.call(); // bar(v);
// You might capture by copy/move if you prefer (instead of by reference)
我 运行 在将函数作为参数传递到方法中时遇到问题。我的问题是我希望能够传递具有任何类型和数量的参数的任何 void 函数,然后将其存储在数据成员中。我目前所做的是对不带参数的 void 函数进行重载,并对具有 std::any 类型向量参数的 void 函数进行重载,然后为该向量添加一个额外的参数。这是我所做的一个例子:
typedef void (*FunctionT1)();
typedef void (*FunctionT2)(std::vector<std::any>);
class ExampleClass {
public:
void saveFunction(FunctionT1 f) {
emptyFunction = f;
}
void saveFunction(FunctionT2 f, std::vector<std::any> args) {
vectorFunction = f;
vectorFunctionArgs = args;
}
private:
FunctionT1 emptyFunction;
FunctionT2 vecotorFunction;
std::vector<std::any> vectorFunctionArgs;
}
现在这可行,我可以做我想做的事,但这显然是一个非常糟糕的解决方案。有没有办法以其他方式做到这一点? (我在考虑模板包,但无法弄清楚它们是如何工作的)
我想向您展示一个抽象工厂的例子。
对于工厂模式,我们通常会遇到问题,即所有构造函数都应该具有相同的签名。但是我们经常希望使用具有不同参数集的函数。
如果您查看下面的示例,我可以向工厂添加具有任意数量参数的函数。
我知道这不是您想要的,但它可能会提示您如何实现自己的功能。
#include <iostream>
#include <map>
#include <utility>
#include <any>
// Some demo classes ----------------------------------------------------------------------------------
struct Base {
Base(int d) : data(d) {};
virtual ~Base() { std::cout << "Destructor Base\n"; }
virtual void print() { std::cout << "Print Base\n"; }
int data{};
};
struct Child1 : public Base {
Child1(int d, std::string s) : Base(d) { std::cout << "Constructor Child1 " << d << " " << s << "\n"; }
virtual ~Child1() { std::cout << "Destructor Child1\n"; }
virtual void print() { std::cout << "Print Child1: " << data << "\n"; }
};
struct Child2 : public Base {
Child2(int d, char c, long l) : Base(d) { std::cout << "Constructor Child2 " << d << " " << c << " " << l << "\n"; }
virtual ~Child2() { std::cout << "Destructor Child2\n"; }
virtual void print() { std::cout << "Print Child2: " << data << "\n"; }
};
struct Child3 : public Base {
Child3(int d, long l, char c, std::string s) : Base(d) { std::cout << "Constructor Child3 " << d << " " << l << " " << c << " " << s << "\n"; }
virtual ~Child3() { std::cout << "Destructor Child3\n"; }
virtual void print() { std::cout << "Print Child3: " << data << "\n"; }
};
using UPTRB = std::unique_ptr<Base>;
template <class Child, typename ...Args>
UPTRB createClass(Args...args) { return std::make_unique<Child>(args...); }
// The Factory ----------------------------------------------------------------------------------------
template <class Key, class Object>
class Factory
{
std::map<Key, std::any> selector;
public:
Factory() : selector() {}
Factory(std::initializer_list<std::pair<const Key, std::any>> il) : selector(il) {}
template<typename Function>
void add(Key key, Function&& someFunction) { selector[key] = std::any(someFunction); };
template <typename ... Args>
Object create(Key key, Args ... args) {
if (selector.find(key) != selector.end()) {
return std::any_cast<std::add_pointer_t<Object(Args ...)>>(selector[key])(args...);
}
else return nullptr;
}
};
int main()
{
Factory<int, UPTRB> factory{
{1, createClass<Child1, int, std::string>},
{2, createClass<Child2, int, char, long>}
};
factory.add(3, createClass<Child3, int, long, char, std::string>);
// Some test values
std::string s1(" Hello1 "); std::string s3(" Hello3 ");
int i = 1; const int ci = 1; int& ri = i; const int& cri = i; int&& rri = 1;
UPTRB b1 = factory.create(1, 1, s1);
UPTRB b2 = factory.create(2, 2, '2', 2L);
UPTRB b3 = factory.create(3, 3, 3L, '3', s3);
b1->print();
b2->print();
b3->print();
b1 = factory.create(2, 4, '4', 4L);
b1->print();
return 0;
}
通过阅读问题和浏览评论,我认为这是最适合您的问题的,
#include <vector>
class ExampleClass {
public:
ExampleClass() = default;
/**
* Save a function pointer.
*
* @param Function: The function poitner.
* @return The index of the function.
*/
template<class Return = void, class... Args>
size_t SaveFunction(Return(*Function)(Args... args))
{
mFunctions.insert(mFunctions.end(), Function);
return mFunctions.size() - 1;
}
/**
* Call a saved function.
*
* @tparam Return: The return type of the function.
* @param index: The index of the function.
* @param args: The arguments the function requires.
* @return The return of the function.
*/
template<class Return = void, class... Args>
Return CallFunction(size_t index, const Args&... args)
{
typedef Return(*Function)(Args...);
return reinterpret_cast<Function>(mFunctions[index])(args...);
}
private:
std::vector<void*> mFunctions;
};
然后你就可以这样保存和调用任何函数了,
void Function() { std::cout << "Hello World\n"; }
void Add(int x, int y) { std::cout << x + y << std::endl; }
int main()
{
ExampleClass c;
size_t f1 = c.SaveFunction(Function);
size_t f2 = c.SaveFunction(Add);
c.CallFunction(f1);
c.CallFunction(f2, 1, 2);
}
这适用于具有任意数量参数的任何函数。
注意:如果 return 类型总是 void
,您可以将 Return
替换为 void
。
据我了解,您想调用一个函数 void()
,其中调用者可能会使用绑定参数注册其他函数类型。您可以使用 std::function
:
class ExampleClass {
public:
void saveFunction(std::function<void()> f) {
this->f = f;
}
void call() { f(); }
private:
std::function<void()> f;
};
有使用
void foo();
void bar(std::vector<std::any>);
std::vector<std::any> v;
ExampleClass ex;
ex.SaveFunction(&foo); ex.call(); // foo();
ex.SaveFunction([&]() { bar(v); }); ex.call(); // bar(v);
// You might capture by copy/move if you prefer (instead of by reference)