gpt4 book ai didi

c++为函数表建立一个名称,函数具有不同的签名

转载 作者:行者123 更新时间:2023-11-30 04:55:03 35 4
gpt4 key购买 nike

我想知道,是否可以在 C++ 中为函数表构建一个名称,例如 map<string, function handle> .但是

  1. 这些函数具有不同的签名。我可以假设它们具有与 void 相同的返回类型.

  2. 我在想定义类似的东西,

    struct ftable
    {
    std::string name;
    void (void* pfun)(); // this is only for one function signature
    };

但是如何让它适用于不同类型的函数呢?

我问了一个相关问题here .在那个问题中,我尝试将函数存储到某个容器中,但我意识到我无法使用占位符存储函数(请参见以下代码)。这可能用 C++ 实现吗?谢谢!

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.
}

更新:我想要的是插件开发。我有一个服务器和一个客户端。我可以在客户端编写我的函数,并将其构建为共享库,然后将该共享库发送到服务器以及告诉服务器加载它的信号。我希望服务器程序可以从共享库中加载具有不同签名的函数,而无需重新启动或重建。这是可能的,还是我必须修复签名并限制所有共享功能?

最佳答案

这是可能的,但在某些时候您将需要知道返回和参数类型。

您可以使用类型删除类来隐藏返回/参数类型,然后存储类型删除类。像这样的简单实现就足够了,

#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";
}

如果这是我们真正需要做的,我建议查找各种类型删除的方法。

我认为您要解决的问题可能有更简单的解决方案。如果您可以提供更多详细信息,也许我们可以提供帮助?

编辑

与您提供的代码更相关的示例...

/* 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);

}

编辑 V2

这更像是一个猜测。我不确定你是否应该这样做(绝​​对不是在一些有趣的实验之外)或者它是否会起作用。如果不同函数的不同参数的数量已知且有限,则这是一种可能的方法。这将需要一种称为库插入的技术,我对此了解不多。

首先在主程序中定义这个枚举和一个工厂函数。枚举将描述每个可能的参数范围。

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 */

}
}

关于c++为函数表建立一个名称,函数具有不同的签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53312744/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com