【发布时间】:2017-01-16 06:14:42
【问题描述】:
我正在尝试创建一个将注册接收器的事件管理器。为此,我希望能够构造一个带有给定参数的std::function。但是,我希望最终用户可以轻松理解错误。我曾想过使用 SFINAE 和依赖于类型的 static_assert 来执行此操作,但我遇到了麻烦,因为这两个函数在有效输入上变得模棱两可。此外,我希望用户可以收到多个错误原因。由于有两个故障点(提供无效的函子并提供错误的事件类型),我希望总共有 3 个函数,第一个是正确输入的函数,然后是不正确的输入(而不是 4 个函数)每个状态组合)。
这可以用 c++17 的 if constexpr 解决,但我的目标平台是 c++14,所以需要使用其他方法。
我当前的尝试(仅检查一种错误状态):
template <typename Event, typename Func>
auto register(Func &&func)
-> decltype(func_t<Event>(std::forward<Func>(func)), void()) {}
template <typename Event, typename Func>
void register(Func &&) {
static_assert(meta::delay_v<Func>, "Function object cant be constructed by function");
}
meta::delay_v 等于false,但取决于其参数,因此在调用函数之前不会触发static_assert。
一个更复杂的用例是
template <typename Event, typename Func>
auto register(Func &&func)
-> decltype(func_t<Event>(std::forward<Func>(func))
,meta::is_in_tuple<Event, Events_Tuple>
,void()) {}
因此,如果第一个测试失败(func_t 构造),那么我们将对此进行 static_assert,如果第二个测试失败,我们将对此进行static_assert。因此,如果第一个测试失败,无论第二个测试如何,我们都会失败一些静态断言。然后,如果第一个测试通过,我们将打印第二个测试失败的信息。不必重写测试将是一个非常好的奖励。
【问题讨论】:
-
使用标签调度+简单的重载,或者实现/使用detection idiom。
-
@ildjarn 有了检测习语,我不需要为 2 个可能的错误点提供 4 个函数吗?因为对于每个函数,我都必须检查所有错误点的一个特定组合。除非我没有看到让我只有 3 个函数来处理 2 个错误(以及 4 个函数来处理 3 个错误)。
-
您将编写 1 + ErrorN 函数;分派到正确错误/成功函数的公共 API 是通用样板,您只需编写一次并用于每组函数。
-
是的,我现在明白了,谢谢。
标签: c++ templates c++14 sfinae