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

标签 c++ function c++11 c++17

我想知道,是否可以在 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/

相关文章:

javascript - 单击时未调用函数内的 Coffeescript 函数

jQuery 调用预定义函数

c++ - 将函数模板限制为特定类型?

c++ - 最小/最大/步长函数和 "body of constexpr function ... not a return-statement"

c++ - 如何在回溯中显示 lambda 函数?

c++ - Fortran、ISO C 绑定(bind)和 std::string

c++ - 鉴于其完整路径名会因计算机而异,如何引用要在 C++ 中打开的文件?

C++ 芯片对计算问题

c++ - 如何正确使用dirent.h

javascript - 禁用和重新启用功能、静音和取消静音