【问题标题】:How to define a vector of functions that accepts different parameter types in c++?如何在 C++ 中定义一个接受不同参数类型的函数向量?
【发布时间】:2020-02-05 15:19:13
【问题描述】:

我正在为自己做一个挑战,并在不使用类和类相关机制的情况下用 C++ 编写程序。附加条件是我可以使用 stl 中的所有内容并具有完全的类型安全性,这意味着没有原始指针或从一种类型转换为另一种类型。我现在处于一种情况,我不确定如何继续我对自己施加的限制。

问题:我想创建一个 std::vector 函数,但这些函数中的每一个都可能采用不同的数据类型,并且仅对该类型进行操作。示例:

struct DataAndFunction {
    AnyDataType data;
    std::function<void(AnyDataType&)> functionOperatingWithData;
};
...
std::vector<DataAndFunction> listOfFunctions;
...
for(auto& dataAndFunc : listOfFunctions) {
    dataAndFunc.functionOperatingWithData(dataAndFunc.data);
}

那么就会有不同类型的AnyDataType 和伴随的函数。

我知道这可以通过两种方式解决:

  1. 类使用多态性,其中

    std::vector&lt; DataAndFunction &gt; listOfFunctions;

只需要一个基类作为模板参数,并且会有虚拟方法,由子类实现,每个子类都有自己的私有数据成员,但我的挑战是不要使用这种模式。

  1. 我可以将void* 作为数据和函数签名传递,并且在每个函数内部我会将数据转换为适当的类型,但我想使用类型安全且仅使用智能指针

我还可以通过添加模板参数使DataAndFunction 结构成为通用结构,但是如何创建一个不仅可以填充DataAndFunction&lt;int&gt; 的向量,还可以填充任何模板参数?

如何以更实用的方式解决这个问题?一个函数式解决方案在 C++ 中的外观如何,它将对一个函数列表进行操作,每个函数都采用不同类型的参数?当然不使用继承。

或者我只是在问如何模拟虚拟表?

【问题讨论】:

  • 我认为,当您了解如何处理约束时,您应该进行约束。如果你需要函数式,为什么不使用函数式语言?
  • DataAndFunction&lt;int&gt; dint; DataAndFunction&lt;char&gt; dchar; std::vector&lt;std::function&lt;void()&gt;&gt; funcs{[&amp;](){ dint.f(dint.data); }, [&amp;](){ dchar.f(dchar.data); }}; for(auto&amp; f : funcs) { f(); }?
  • 为什么不让你的向量保持 std::function&lt;void&gt; 并在 lambda 中捕获你的数据?
  • @Jarod42 这就是我一直在寻找的答案,而这些 lambdas 正是我缺失的部分。谢谢!如果你把它写成答案,我可以接受。

标签: c++ functional-programming


【解决方案1】:

看来你只需要std::function&lt;void()&gt;:

DataAndFunction<int> dint;
DataAndFunction<char> dchar;
std::vector<std::function<void()>> funcs{
    [&](){ dint.f(dint.data); },
    [&](){ dchar.f(dchar.data); },
    [](){ std::cout << "Hello world\n"; }
};

for (auto& f : funcs) {
    f();
}

【讨论】:

    【解决方案2】:

    您知道吗,C++ 是一种强类型语言。这意味着您不能像其他语言(如 Python)那样拥有泛型变量。

    在C语言中,解决方法是使用指向void (void*)的点,但是很难管理并且容易出错。

    C++17 提供了 2 个优雅的解决方案,您可以使用它们:

    std::anystd::variant.

    【讨论】:

      【解决方案3】:

      这是您可以存储以不同类型作为参数的函数向量的一种方式,它还接受不同数量的参数。它使用 std::any、std::pair 和 std::tuple 来包含函数及其参数。 std::any 比void * 安全得多,但是由于 std::any 存储了大量数据,因此内存开销更大。

      程序简单地输出:“Hello World!”

      #include <any>
      #include <tuple>
      #include <string>
      #include <vector>
      #include <utility>
      #include <iostream>
      #include <functional>
      
      std::vector<std::pair<std::function<void(const std::any&)>, std::any>> funcList;
      
      template <typename F, typename...T>
      std::size_t insertAnyFunc(const F &func, const T&...params) {
          auto t = std::make_tuple<const T&...>(params...);
          funcList.push_back({
              [f = func](const std::any &a) {
                  if constexpr (sizeof...(T) == 0)
                      f();
                  else
                      std::apply(f, std::any_cast<const std::tuple<T...> &>(a));
              }, std::make_any<std::tuple<T...>>(t)
          });
          return funcList.size();
      }
      
      void execAnyFunc(const std::size_t &ID) {
          if (ID < funcList.size())
              funcList.at(ID).first(funcList.at(ID).second);
      }
      
      int main (void) {
          insertAnyFunc([](const std::string &s){ std::cout << s; }, std::string("Hello World!\n"));
          execAnyFunc(0);
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2016-07-07
        • 2013-07-14
        • 2011-08-27
        • 2012-09-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-22
        • 1970-01-01
        相关资源
        最近更新 更多