C++ 对象将模板化函数和参数保留为稍后调用的成员
C++ object keeps templated function and args as members to call later
我有一个 class Door
实现了方法 LockCheck()
,还有一个 class Stove
实现了方法 BurnerCheck()
。我想要一个 class 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)
classHouse
"looks"应该喜欢什么?
到目前为止,我有,
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 问题,例如 this and this。
您可以将所有参数存储为一个元组。然后,您可以通过将元组解包为函数参数来调用 safety_func_
。解包可以直接在 C++17 中使用 std::apply.
完成
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)如果写模板classHouse
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) {}
其中检查方法的参数是 "unknown"(而且,我想,类型不同)当你定义 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
不感兴趣(如果您可以忽略它),请将 House
设为非模板 class 并设为可变参数它的模板构造函数;像
class House
{
public:
template <typename ... Args, typename F>
House (Args ... as, F f)
2) 如果你有一个模板 function/method/constructor 带有一些固定参数和可变参数列表,将可变参数列表放在 last 位置,所以编译器可以从参数中推导出可变类型列表,不需要显式显示它。
所以前面的构造函数变成了
template <typename F, typename ... Args>
House (F f, Args ... as)
3) 据我所知,没有办法将指向实际方法的指针传递给函数 o 给变量;所以没有
auto stove_check = stove.BurnerCheck;
并且没有 stove_check
作为 House
构造函数的参数。
我知道的解决这类问题的常用方法是传递对象 (stove
) 和指向 BurnerCheck
方法的指针,而不是对象 class ;像
auto house { House(stove, &Stove::BurnerCheck, /* variadic args */) };
现在构造器变为
template <typename T, typename M, typename ... Args>
House (T t, M m, Args ... as)
你可以调用 stove
的 BurnerCheck()
方法作为
(t.*m)(as...)
现在我建议 House
class:一个 class 和一个 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
模板 class,仅使用 ReturnType
参数并调整class 因此。
我有一个 class Door
实现了方法 LockCheck()
,还有一个 class Stove
实现了方法 BurnerCheck()
。我想要一个 class 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)
classHouse
"looks"应该喜欢什么?
到目前为止,我有,
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 问题,例如 this and this。
您可以将所有参数存储为一个元组。然后,您可以通过将元组解包为函数参数来调用 safety_func_
。解包可以直接在 C++17 中使用 std::apply.
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)如果写模板classHouse
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) {}
其中检查方法的参数是 "unknown"(而且,我想,类型不同)当你定义 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
不感兴趣(如果您可以忽略它),请将 House
设为非模板 class 并设为可变参数它的模板构造函数;像
class House
{
public:
template <typename ... Args, typename F>
House (Args ... as, F f)
2) 如果你有一个模板 function/method/constructor 带有一些固定参数和可变参数列表,将可变参数列表放在 last 位置,所以编译器可以从参数中推导出可变类型列表,不需要显式显示它。
所以前面的构造函数变成了
template <typename F, typename ... Args>
House (F f, Args ... as)
3) 据我所知,没有办法将指向实际方法的指针传递给函数 o 给变量;所以没有
auto stove_check = stove.BurnerCheck;
并且没有 stove_check
作为 House
构造函数的参数。
我知道的解决这类问题的常用方法是传递对象 (stove
) 和指向 BurnerCheck
方法的指针,而不是对象 class ;像
auto house { House(stove, &Stove::BurnerCheck, /* variadic args */) };
现在构造器变为
template <typename T, typename M, typename ... Args>
House (T t, M m, Args ... as)
你可以调用 stove
的 BurnerCheck()
方法作为
(t.*m)(as...)
现在我建议 House
class:一个 class 和一个 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
模板 class,仅使用 ReturnType
参数并调整class 因此。