C++ 对象将模板化函数和参数保留为成员以便稍后调用

标签 c++ c++11 templates variadic-templates std-function

我有一个实现方法 LockCheck() 的类 Door,以及具有方法 BurnerCheck() 的类 Stove 。我想要一个类 House ,它采用 Door::LockCheckStove::BurnerCheck 作为构造函数参数,以及一组未知的参数给定的函数。然后,House 将存储该函数及其参数,以便稍后可以调用它们。例如,

auto stove = Stove();
auto stove_check = stove.BurnerCheck;
auto burner_args = std::make_tuple<bool, bool>(true, false);
auto house = House(burner_args, stove_check);
// do some other stuff...
house.check_safety();  // internally calls stove.BurnerCheck(burner_args)

House 类“看起来”应该是什么样子?

到目前为止我已经,

template <typename ReturnType, typename... Args>
class House {

public:

    House(Args... args, std::function<ReturnType(Args...)> func)
        : input_args_(std::forward_as_tuple(args...)),
          safety_func_(func) {}
    };

private:

    Args... input_args_;  // Is this the correct declaration?
    std::function<ReturnType(Args...)> safety_func_;
};

注释:

  • C++11

  • 我已经看过相关的 SO 问题,例如 thisthis .

最佳答案

一些初步考虑。

1) 如果你写了一个模板类House

template <typename ReturnType, typename... Args>
class House {
  // ...

    House(Args... args, std::function<ReturnType(Args...)> func)
        : input_args_(std::forward_as_tuple(args...)),
          safety_func_(func) {}

如果检查方法的参数是“未知”(并且我认为不同类型不同),则在定义 House 时您必须知道该参数对象和你有不同的House类型(一个 House 类型用于 Door 的检查,一个 House 类型用于 Stove 的检查,等等)并且(在 C++17 之前)您不能声明 House对象简单地为

auto house = House(burner_args, stove_check);

但是你必须明确模板类型;诸如此类的东西

House<void, bool, bool> house{burner_args, stove_check};

建议:在您对 ReturnType 不感兴趣时检查方法(如果你可以忽略它) make House一个非模板类并为其创建一个可变模板构造函数;诸如此类的东西

class House
 {
   public:
      template <typename ... Args, typename F>
      House (Args ... as, F f) 

2) 如果您有一个带有一些固定参数和可变参数列表的模板函数/方法/构造函数,请将可变参数列表放在 last 位置,以便编译器可以推断出来自参数的类型的可变列表,不需要显式地显示它。

所以前面的构造函数变成了

  template <typename F, typename ... Args>
  House (F f, Args ... as) 

3) 据我所知,没有办法将指向函数 o 的实际方法的指针传递给变量;所以不

auto stove_check = stove.BurnerCheck;

没有stove_check作为 House 的参数构造函数。

我知道解决此类问题的常用方法是传递对象( stove )和指向 BurnerCheck 的指针。方法引用的是类,而不是对象;诸如此类的东西

auto house { House(stove, &Stove::BurnerCheck, /* variadic args */) };

现在构造函数变成了

  template <typename T, typename M, typename ... Args>
  House (T t, M m, Args ... as) 

您可以调用BurnerCheck()方法stove

  (t.*m)(as...)

现在我建议House类:具有 std::function<void(void)> 的类已初始化的成员,位于 House构造函数,带有捕获对象、指针方法和参数的 lambda。

还有一个check_safety()只需调用该成员的方法。

内容如下

class House
 {
   private:
      std::function<void(void)> fn;

   public:
      template <typename T, typename M, typename ... Args>
      House (T t, M m, Args ... as) : fn{[=]{ (t.*m)(as...); }}
       { }

      void check_safety ()
       { fn(); }
 };

以下是一个完整的工作示例

#include <iostream>
#include <functional>

struct Door
 { void LockCheck (int, long) const { std::cout << "Door" << std::endl; } };

struct Stove
 { void BurnerCheck (char) const { std::cout << "Stove" << std::endl; } };

class House
 {
   private:
      std::function<void(void)> fn;

   public:
      template <typename T, typename M, typename ... Args>
      House (T t, M m, Args ... as) : fn{[=]{ (t.*m)(as...); }}
       { }

      void check_safety ()
       { fn(); }
 };

int main ()
 {
   auto stove { Stove{} };
   auto door { Door{} };
   auto house1 { House{stove, &Stove::BurnerCheck, 'a'} };
   auto house2 { House{door, &Door::LockCheck, 1, 2L} };

   std::cout << "Some other stuff" << std::endl;

   house1.check_safety();
   house2.check_safety();
 }

如果您对检查方法返回的值感兴趣...我想您可以制作 House仅包含 ReturnType 的模板类参数并相应地调整类别。

关于C++ 对象将模板化函数和参数保留为成员以便稍后调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50501126/

相关文章:

javascript - 如何在使用 fastify 服务之前替换 Javascript 变量?

templates - 也许输入 D

c++ - 将 PPM 图像转换为灰度 C++

c++ - 无法弄清楚为什么这不起作用

c++ - 强制评估 constexpr 静态成员

c++ - 使用不完整类型参数化的模板的外部模板

c++ - 将 boost::signals2::trackable 与 lambda 一起使用

CSS/XHTML - overlay.png 在此模板中的作用是什么?

python - 将大型复杂数组从 Python 传递到 C++ - 我的最佳选择是什么?

c++ - 如何获得为给定字符手动设置的字形?