我有一个实现方法 LockCheck()
的类 Door
,以及具有方法 BurnerCheck() 的类
。我想要一个类 Stove
House
,它采用 Door::LockCheck
或 Stove::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_;
};
注释:
最佳答案
一些初步考虑。
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/