c++ 编写一个类,接受任何类型的带约束的Callable对象

tcomlyy6  于 2024-01-09  发布在  其他
关注(0)|答案(1)|浏览(147)

我正在做一个小项目,试图创建一个系统,在这个系统中,我有几个类Rule的示例,每个示例执行一个操作,然后根据操作的结果将控制传递给下一个规则。操作可以是任何东西,可以接受任何数量的参数,也可以不接受任何参数,但是总是返回一个Message(enum)。我希望能够以更通用的方式编写操作:作为一个函数,一个lambda,函数指针等,这样我就不受特定语法的约束
到目前为止,代码如下所示

  1. #include <concepts>
  2. #include <map>
  3. #include <unordered_map>
  4. #include <functional>
  5. #include <iostream>
  6. enum Message {
  7. success,
  8. failure,
  9. nothing
  10. };
  11. class BaseRule {};
  12. template <typename F, typename ...Args> requires std::invocable<F, Args...>
  13. class Rule: public BaseRule {
  14. private:
  15. std::map<Message, BaseRule*> successors; //a feature allowing to chain rules, unused at this moment
  16. template <typename... Ts> struct undef; // for testing purposes only
  17. public:
  18. F action;
  19. Rule(F _action) : action(_action) {};
  20. void addSuccessor(const Message, BaseRule*);
  21. void removeSuccessor(const Message);
  22. template <typename... ExecuteArgs>
  23. void execute(ExecuteArgs&&... args) {
  24. //execute the action, and call the next rule's action according to the Message returned
  25. if constexpr (std::is_invocable_v<F, ExecuteArgs...>)
  26. std::invoke(action, std::forward<ExecuteArgs>(args)...);
  27. else
  28. undef<F, ExecuteArgs...> _; // for testing purposes, expected to fail and give me the types of F and ExecuteArgs in the error message
  29. };
  30. };
  31. class App {
  32. private:
  33. std::unordered_map<unsigned int, std::function<void()>> boundActions;
  34. public:
  35. template <typename F, typename ...Args> requires std::invocable<F, Args...>
  36. void bindInput(const unsigned int _key, BaseRule* _rule, Args... _args) {
  37. auto callable = [_rule, _args...]() {
  38. static_cast<Rule<F, Args...>*>(_rule)->execute(_args...);
  39. };
  40. boundActions[_key] = callable;
  41. };
  42. template <typename F, typename ...Args> requires std::invocable<F, Args...>
  43. void launch(Rule<F> _startingPoint, Args... args) {
  44. _startingPoint.execute(args...);
  45. loop();
  46. };
  47. void loop() {
  48. while (!quit) {
  49. for (unsigned int i = 0; i < 256; ++i) {
  50. if (downKeys[i]) {
  51. auto it = boundActions.find(i);
  52. if (it != boundActions.end())
  53. it->second(); // Invoke the stored callable object
  54. }
  55. }
  56. }
  57. };
  58. };
  59. int main() {
  60. App app = App();
  61. //app is captured in the lamba to perform some logic
  62. Rule init = Rule([&app]() -> Message {
  63. std::cout << "Initialization" << std::endl;
  64. return nothing;
  65. });
  66. //This fails
  67. Rule mark = Rule([&app](const unsigned int _target) -> Message {
  68. std::cout << "Mark" << std::endl;
  69. return success;
  70. });
  71. app.bindInput<decltype(init.action)>(32, &init);
  72. app.bindInput<decltype(mark.action)>(65, &mark, 0); //Thus, this also fails
  73. app.bindInput<decltype(mark.action)>(90, &mark, 1); //Same
  74. app.launch(&init);
  75. return 0;
  76. }

字符串
这段代码让我创建了规则init,但未能示例化规则mark,出现了几个与模板参数推导有关的错误,主要是C2748 'Rule<F> Rule(Rule<F>)' : could not deduce template argument for 'Rule<F>' from 'main::<lambda_2>' on mark Rule instantiation(其他错误来自于示例化mark失败)。我还尝试用函数替换lambda,但是错误仍然存在。尝试使用Rule<decltype(markF)> mark = Rule<decltype(markF)>(markF);markF是一个与之前用于示例化mark的lambda具有相同行为的函数)添加了一个新的C7602错误,相关的约束不满足。但是使用没有参数的函数工作得很好。
作为旁注,我注意到另一个问题(如果解决当前问题还没有解决,它将有自己的问题)。

alen0pnh

alen0pnh1#

你永远不能推断出Args...是一个空包以外的任何东西,因为没有任何东西从F指定它。一般来说,有多个可能的Args...使得std::invocable<F, Args...>为真。
最简单的修复方法是从Rule的模板参数中删除Args...
See it on coliru

相关问题