C ++对象保留模板化函数,args作为成员稍后调用

时间:2018-05-24 04:43:24

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

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

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_;
};

注意:

2 个答案:

答案 0 :(得分:1)

您可以将所有参数存储为元组。然后,您可以通过将元组解压缩为函数参数来调用safety_func_。可以使用std::apply直接在C ++ 17中完成解包。

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

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

    // Require C++17
    ReturnType call_safety() {
        return std::apply(safety_func_, input_args_);
    }
private:

    std::tuple<Args...> input_args_;
    std::function<ReturnType(Args...)> safety_func_;
};

对于纯C ++ 11元组解包解决方案,请参阅this post

答案 1 :(得分:1)

一些初步考虑。

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) {}

检查方法的参数是&#34;未知&#34; (并且,我想,不同于类型)你必须在定义House个对象时知道这些参数,并且你有HouseHouse类型{{1}对Door的支票进行House类型检查等等,并且(在C ++ 17之前)您无法声明{{1}对象只是作为

Stove

但你必须明确模板类型;

House

建议:您对检查方法的auto house = House(burner_args, stove_check); 不感兴趣(如果可以忽略它),请使House<void, bool, bool> house{burner_args, stove_check}; 成为非模板类​​并为其创建可变参数模板构造函数;

ReturnType

2)如果你有一个带有一些固定参数和一个可变参数列表的模板函数/方法/构造函数,请将参数的可变参数列表放在 last 位置,这样编译器就可以推导出参数的可变参数列表,不需要显式。

所以前面的构造函数变为

House

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

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

并且没有 template <typename F, typename ... Args> House (F f, Args ... as) 作为auto stove_check = stove.BurnerCheck; 构造函数的参数。

我知道这种问题的常用方法是传递对象(stove_check)和指向类的House方法的指针,而不是对象;

stove

现在构造函数变为

BurnerCheck

您可以将auto house { House(stove, &Stove::BurnerCheck, /* variadic args */) }; 的{​​{1}}方法称为

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

现在我建议的BurnerCheck()类:一个stove成员的类,在 (t.*m)(as...) 构造函数中初始化,带有捕获对象,指针方法和参数的lambda。

一个只调用该成员的House方法。

以下内容

std::function<void(void)>

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

House

如果您对检查方法返回的值感兴趣...我想您可以使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(); } }; 参数的模板类,并因此调整类。