我不能也不会用细节来烦你,但我的系统有这些特定要求:
Call
函数调用。从概念上讲,这非常简单:我们注册一个操作,然后通过其名称和给定类型的参数调用该操作。这意味着可以在运行时从代码中的任何位置进行调用。
最小的可重现示例:https://onlinegdb.com/qNErEq_85
目前,示例操作如下所示:
bool DoAction(const int Target, ...)
{
va_list args;
va_start(args, Target); // Initialize the va_list with the last named parameter
// Assume the first argument after Targets is a std::string
const char* stringArg = va_arg(args, const char*); // Get the string argument
std::string myString(stringArg); // Convert it to std::string
va_end(args); // Clean up the va_list
std::cout << myString << " \n";
return true;
}
这就是
Call()
函数的样子:
bool Call(const int Target, ...) override
{
std::cout << "called";
va_list args;
va_start(args, Target);
bool returnValue = (Instance->*ActionFunction)(Target, args);
va_end(args);
return returnValue;
}
此实现的关键问题是
va_list
消耗了参数,因此它们不能嵌套。
我尝试用模板替换
virtual
,但std::map<std::string, Action*> RegisteredActions;
仍然需要推导。然而, dynamic_cast
转换为派生类型是不可能的,因为 Call()
不应该采用除函数名和函数参数之外的任何模板或参数(否则使用这个系统就没有多大意义)。
我没有尝试过的解决方案:
Call()
成为宏。这可能行得通,但我还没弄清楚如何。网站上没有这方面的问题,主要是询问具体的编译错误。我的问题是如何实现特定类型的运行时功能。
如何创建嵌套可变参数函数?
您可以摆脱 C 变量并使用 C++ 中的类型:
std::map<std::string, std::function<bool(int, std::vector<std::any>)>> RegisteredActions{
{ "FooAction", &FooAction},
// ...
};
RegisteredActions["BarAction"] = &FooAction;
函数看起来像:
bool FooAction(int target, std::vector<std::any> v) {
if (v.size() != 1) { // check size
return false;
}
if (auto* s = std::any_cast<std::string>(&v[0])) { // check type
std::cout << target << ": " << *s << std::endl;
return true;
}
return false;
}
注意: 注意类型和类型转换:
const char*
不是 std::string
assert(FooAction(42, "const char*") == false);
assert(FooAction(42, "std::string"s) == true);
调用方式如下:
int target = 42// ...;
std::vector<std::any> args = { "Hello"s };
const auto it = RegisteredActions.find(Name);
if (it == RegisteredActions.end())
{
// ERROR: No action of name has been registered
throw std::runtime_error("Action not found");
}
auto res = it->second(target, args);