c++;建立一个函数名表,函数有不同的签名 我想知道,如果可以在C++中构建一个函数表的名称,比如“代码> map < /COD>”。但是
这些函数具有不同的签名。我可以假设它们的返回类型与c++;建立一个函数名表,函数有不同的签名 我想知道,如果可以在C++中构建一个函数表的名称,比如“代码> map < /COD>”。但是,c++,function,c++11,c++17,C++,Function,C++11,C++17,这些函数具有不同的签名。我可以假设它们的返回类型与void相同 我在想定义一下 struct-ftable { std::字符串名; void(void*pfun)(;//这仅用于一个函数签名 }; 但是如何使它适用于不同类型的功能呢 我问了一个相关的问题。在这个问题中,我尝试将函数存储到某个容器中,但我意识到我不能使用占位符存储函数(请参见下面的代码)。C++可以这样做吗?谢谢 template <typename F, typename ... Args> std::functi
void
相同
struct-ftable
{
std::字符串名;
void(void*pfun)(;//这仅用于一个函数签名
};代码>
template <typename F, typename ... Args>
std::function<void()> MapFun (F const & f, Args const & ... args)
{ return [=]{ f(args...); }; }
void userFun1 (int i1, int i2)
{ std::cout << "uf1, " << i1 << ", " << i2 << std::endl; }
int main ()
{
auto l1 = MapFun(userFun1, 1, 2);
std::unordered_map<std::string, std::function<void()>> func_map;
func_map["userFun1"] = std::bind(l1); // this is okay;
//func_map["userFun1"] = std::bind(userFun1, std::placeholders::_1, std::placeholders::_2); // this is wrong;
//auto lll1 = MapFun(userFun1, std::placeholders::_1,std::placeholders::_2); // also wrong.
}
模板
std::函数MapFun(F常量和F,Args常量和…Args)
{return[=]{f(args…;};};}
void userFun1(inti1,inti2)
{std::cout如果在创建std::function
的对象时,您知道函数签名,那么您可以执行以下操作
#include <iostream>
#include <functional>
#include <unordered_map>
void userFun1 (int i1, int i2)
{
std::cout << "uf1, " << i1 << ", " << i2 << std::endl;
}
int main()
{
std::unordered_map<std::string, std::function<void()>> func_map;
func_map["userFun1"] = std::bind(userFun1,1,2);
func_map["userFun1"]();
int i1{2},i2{3};
func_map["userFun1.1"] = std::bind(userFun1,std::ref(i1),std::ref(i2));
func_map["userFun1.1"]();
i1 = 3;
i2 = 4;
func_map["userFun1.1"]();
return 0;
}
#包括
#包括
#包括
void userFun1(inti1,inti2)
{
std::cout这是可能的,但在某个时候,您需要知道返回和参数类型
您可以使用类型擦除类隐藏返回/参数类型,然后存储类型擦除类
#include <iostream>
#include <functional>
#include <unordered_map>
class MyLambda {
public:
MyLambda() = default;
virtual ~MyLambda() = default;
};
template <typename T>
class HiddenLambda : public MyLambda {
static_assert(std::integral_constant<T, false>::value, "Template parameter needs to be of function type.");
};
template <typename Ret, typename... Args>
class HiddenLambda<Ret(Args...)> : public MyLambda {
public:
HiddenLambda(std::function<Ret(Args...)> _fun) : fun_(_fun) { }
Ret operator() (Args... args) {return fun_(args...);}
private:
std::function<Ret(Args...)> fun_;
};
int main() {
std::unordered_map<std::string, std::shared_ptr<MyLambda>> my_lambdas;
my_lambdas.insert(std::make_pair("fun1", std::shared_ptr<MyLambda>(
new HiddenLambda<size_t(std::string)>(
[](std::string s) { return s.size(); } // <- lambda you want to store
)
)
));
my_lambdas.insert(std::make_pair("fun2", std::shared_ptr<MyLambda>(
new HiddenLambda<int(int)>(
[](int x) { return x * 5; } // <- lambda you want to store
)
)
));
auto it = my_lambdas.find("fun1");
/* Get the function we want! */
std::shared_ptr<MyLambda> a_lam = it->second;
/* Need to know the types to actually use it though */
HiddenLambda<size_t(std::string)>& actual_lam = dynamic_cast<HiddenLambda<size_t(std::string)>&>(*a_lam);
std::cout << actual_lam("how long is this string?") << "\n";
}
#包括
#包括
#包括
类MyLambda{
公众:
MyLambda()=默认值;
virtual~MyLambda()=默认值;
};
模板
HiddenLambda类:公共MyLambda{
静态_断言(std::integral_constant::value,“模板参数必须是函数类型”);
};
模板
HiddenLambda类:公共MyLambda{
公众:
HiddenLambda(std::function _-fun):fun(_-fun){
Ret运算符()(Args…Args){return(Args…;}
私人:
std::函数fun;
};
int main(){
std::无序映射我的lambdas;
我的lambdas.insert(std::make_pair(“fun1”),std::shared_ptr(
新希登兰姆达酒店(
[](std::string s){返回s.size();}你为什么认为你需要这个?听起来像是XY问题。你想解决的潜在问题是什么?在你从地图中检索函数后,你怎么知道它的签名是什么?@ RaymondChen,我想你是对的。C++是一种需要在编译时知道类型的语言。我已经更新了我的问题,“超级,谢谢你。”注释如果您在编译时知道签名(例如,“名为bob
的项始终是void(*)(int,int)
”),那么您可以将普通函数指针转换为void(*)(
)进行存储,然后将其转换为void(*)(int,int)
检索后。不同签名的函数指针可以在不损失保真度的情况下相互转换,但在使用它们调用函数之前,必须转换回原始类型。如果转换到错误的签名,然后尝试调用函数,则结果未定义(即“坏”).static_assert
仅涵盖视图数据类型(浮点类型如何?类/结构?)。更好:不要实现模板!谢谢你的回答。但是当从映射中获取函数句柄时,它仍然需要知道类型。它具有与使用std::vector
相同的限制。我已经更新了我的问题,你有什么其他建议吗?@J.Yang你总是需要知道签名。在代码中的某个点你需要给函数提供参数,在那一点上你需要知道所有参数的类型。我已经添加了一个可以帮助的编辑。@ J.Yang.请让我知道如果你工作了,我很想知道你到底做了什么。你对这个答案很满意,请考虑接受它。@巴斯托感谢你的病人。。我需要考虑一下你的编辑V2。如果这不起作用,我想我会修复共享函数的签名。因此它将接受多个向量。如果我想发送几个int输入,我必须将它们全部放在一个向量中,并在函数开始时取出。谢谢你的回答。std::ref听起来很棘手。我有更新d我的问题,你认为这是一个解决办法吗?@J.Yang对于你的更新,我认为这是不可能的。对于任何插件系统,都有一套固定的函数调用或API,插件加载程序和插件本身都知道。在你的情况下,你可以创建你的客户端代码的包装器,知道客户端函数的签名和什么这些值需要传递给客户机函数,并从服务器代码中调用这个包装函数。希望这会有所帮助!
/* include above classes and includes */
void myfunc(int x, int y) {
std::cout << "uf1, " << x << ", " << y << std::endl;
}
int main() {
std::unordered_map<std::string, std::shared_ptr<MyLambda>> func_map;
func_map["userFun1"] = std::shared_ptr<MyLambda>(
new HiddenLambda<void(int, int)>( &myfunc ) // <- no args binded, notice the type = void(int,int)
);
func_map["userFun2"] = std::shared_ptr<MyLambda>(
new HiddenLambda<void(int)>( std::bind(myfunc, std::placeholders::_1, 5) ) // <- one args binded, notice the type = void(int)
);
func_map["userFun3"] = std::shared_ptr<MyLambda>(
new HiddenLambda<void()>( std::bind(myfunc, 1, 2)) // <- two args binded, notice the type = void()
);
/* we still need to know the type though,it will be either void(int, int), void(int) or void() */
HiddenLambda<void(int)>& actual_lam = dynamic_cast<HiddenLambda<void(int)>&>(*func_map["userFun2"]);
actual_lam(4);
}
enum Types { kVOID, kINT_INT }; // <- verbosely define all the possible ones you would use
std::pair<Types, std::shared_ptr<MyLambda>> Factory(){
return
{
kVOID, /* <- some sensible default */
std::shared_ptr<MyLambda>(
new HiddenLambda<void()>( []{} )
)
};
}
std::pair<Types, std::shared_ptr<MyLambda>> Factory(){
return
{
kVOID_INT_INT,
std::shared_ptr<MyLambda>(
new HiddenLambda<void(int, int)>( [](int x, int y){ std::cout << (x + y);} )
)
};
}
int main() {
std::unordered_map<std::string, std::pair<Types, std::shared_ptr<MyLambda>>> func_map;
func_map.insert({"fun1", Factory()});
auto it = func_map.find("fun1");
/* always need to be able to deduce they type */
if (it->second.first == kVOID) {
CallHidden(*it->second.second);
}
else if (it->second.first == kINT_INT) {
CallHidden<int, int>(*it->second.second, 3, 4);
} else {
/* other ones you have statically typed */
}
}