我正在做一个小项目,试图创建一个系统,在这个系统中,我有几个类Rule
的示例,每个示例执行一个操作,然后根据操作的结果将控制传递给下一个规则。操作可以是任何东西,可以接受任何数量的参数,也可以不接受任何参数,但是总是返回一个Message
(enum)。我希望能够以更通用的方式编写操作:作为一个函数,一个lambda,函数指针等,这样我就不受特定语法的约束
到目前为止,代码如下所示
#include <concepts>
#include <map>
#include <unordered_map>
#include <functional>
#include <iostream>
enum Message {
success,
failure,
nothing
};
class BaseRule {};
template <typename F, typename ...Args> requires std::invocable<F, Args...>
class Rule: public BaseRule {
private:
std::map<Message, BaseRule*> successors; //a feature allowing to chain rules, unused at this moment
template <typename... Ts> struct undef; // for testing purposes only
public:
F action;
Rule(F _action) : action(_action) {};
void addSuccessor(const Message, BaseRule*);
void removeSuccessor(const Message);
template <typename... ExecuteArgs>
void execute(ExecuteArgs&&... args) {
//execute the action, and call the next rule's action according to the Message returned
if constexpr (std::is_invocable_v<F, ExecuteArgs...>)
std::invoke(action, std::forward<ExecuteArgs>(args)...);
else
undef<F, ExecuteArgs...> _; // for testing purposes, expected to fail and give me the types of F and ExecuteArgs in the error message
};
};
class App {
private:
std::unordered_map<unsigned int, std::function<void()>> boundActions;
public:
template <typename F, typename ...Args> requires std::invocable<F, Args...>
void bindInput(const unsigned int _key, BaseRule* _rule, Args... _args) {
auto callable = [_rule, _args...]() {
static_cast<Rule<F, Args...>*>(_rule)->execute(_args...);
};
boundActions[_key] = callable;
};
template <typename F, typename ...Args> requires std::invocable<F, Args...>
void launch(Rule<F> _startingPoint, Args... args) {
_startingPoint.execute(args...);
loop();
};
void loop() {
while (!quit) {
for (unsigned int i = 0; i < 256; ++i) {
if (downKeys[i]) {
auto it = boundActions.find(i);
if (it != boundActions.end())
it->second(); // Invoke the stored callable object
}
}
}
};
};
int main() {
App app = App();
//app is captured in the lamba to perform some logic
Rule init = Rule([&app]() -> Message {
std::cout << "Initialization" << std::endl;
return nothing;
});
//This fails
Rule mark = Rule([&app](const unsigned int _target) -> Message {
std::cout << "Mark" << std::endl;
return success;
});
app.bindInput<decltype(init.action)>(32, &init);
app.bindInput<decltype(mark.action)>(65, &mark, 0); //Thus, this also fails
app.bindInput<decltype(mark.action)>(90, &mark, 1); //Same
app.launch(&init);
return 0;
}
字符串
这段代码让我创建了规则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错误,相关的约束不满足。但是使用没有参数的函数工作得很好。
作为旁注,我注意到另一个问题(如果解决当前问题还没有解决,它将有自己的问题)。
1条答案
按热度按时间alen0pnh1#
你永远不能推断出
Args...
是一个空包以外的任何东西,因为没有任何东西从F
指定它。一般来说,有多个可能的Args...
使得std::invocable<F, Args...>
为真。最简单的修复方法是从
Rule
的模板参数中删除Args...
。See it on coliru