使用带有 static_assert 的类型别名缩小模板中允许的类型

Narrow down allowed types in templated using type alias with static_assert

在学习基于模板的元编程时,我遇到了以下问题: 我有一个使用类型别名的模板,我想使用 static_assert 缩小允许的类型,但我不确定如何编写它:

using service_func_plain_loop_t = std::function<void(void)>;
using service_func_with_arg_loop_t = std::function<void(std::string)>;
using service_callbacks_t = std::map<event, std::function<bool(void) >>;

template<typename service_loop> using service_functionality_t =
std::pair<service_loop, service_callbacks_t>;
static_assert(
        std::is_convertible<service_loop,service_func_plain_loop_t>.value ||
        std::is_convertible<service_loop,service_func_with_arg_loop_t>.value,
        "service_loop has to be either service_func_plain_loop_t or " 
        "service_func_with_arg_loop_t");

此方法失败,因为 service_loop 未在 static_assert 的范围内声明。检查 classes 时,我可以将断言移动到 class 范围内,但是这里的语法是什么?

您可以编写一个助手 class 来完成 static_assert:

template <typename service_loop>
struct service_functionality {
    static_assert(
        std::is_convertible<service_loop,service_func_plain_loop_t>::value ||
        std::is_convertible<service_loop,service_func_with_arg_loop_t>::value,
        "service_loop has to be either service_func_plain_loop_t or " 
        "service_func_with_arg_loop_t");

    using type = std::pair<service_loop, service_callbacks_t>;   
};

template<typename service_loop> using service_functionality_t =
typename service_functionality<service_loop>::type;

另请注意,它应该是 std::is_convertible<T,U>::valuestd::is_convertible<T,U>{} 而不是 std::is_convertible<T,U>.value。尽管我们可能会在 C++17 中获得 std::is_convertible_v<T,U> 辅助变量模板。

Live Demo