编译期消息分发,两点补充说明

教育   科技   2023-08-20 22:28   陕西  
关于静态消息分发组件,评论最多的一是比较优化,二是时间复杂度
先看看原本的实现:
1template <std::size_t N>
2struct string_literal {
3    constexpr string_literal(char const (&str)[N]) {
4        std::copy_n(str, N, value);
5    }
6
7    friend bool operator==(string_literal const& s, char const* cause) {
8        return std::strncmp(s.value, cause, N) == 0;
9    }
10
11    operator char const*() const {
12        return value;
13    }
14
15    char value[N];
16};
17
18// default implementation
19template <string_literal C>
20inline constexpr auto handler = [] { std::cout << "default effect\n"; };
21
22#define _(name) template<> inline constexpr auto handler<#name>
23
24// opt-in customization points
25_(cause 1) = [] { std::cout << "customization points effect 1\n"; };
26_(cause 2) = [] { std::cout << "customization points effect 2\n"; };
27
28
29template <string_literal... Cs>
30struct dispatcher {
31    template <string_literal C>
32    constexpr auto execute_if(char const* cause) const {
33        if (C == cause) handler<C>();
34    }
35
36    constexpr auto execute(char const* cause) const {
37        (execute_if<Cs>(cause), ...);
38    }
39};
40
41int main() {
42    constexpr string_literal cause_1{ "cause 1" };
43    constexpr dispatcher<cause_1, "cause 2""cause 3"> dispatch;
44    dispatch.execute(cause_1);
45    dispatch.execute("cause 2");
46    dispatch.execute("cause 3");
47}
第一是 std::strncmp 并不是一个编译期函数,但 C++17 的 string_view 提供有编译期的字符串比较运算符重载。因此,改成这样实现更好:

1friend bool operator==(string_literal const& s, char const* cause) {
2    // return std::strncmp(s.value, cause, N) == 0;
3    return std::string_view(s.value) == cause;
4}

第二是当前每次执行时都会进行一次线性查找,时间复杂度为 O(n)。变成 O(1) 也有办法,但是传入的参数就必须也得是编译期数据,否则使用不了。
像是这样:

1template <autostruct compile_time_param {};
2template <string_literal Data> inline auto compile_time_arg = compile_time_param<Data>{};
3
4template <string_literal... Cs>
5struct dispatcher {
6    // ...
7
8    template<string_literal s>
9    constexpr auto execute(compile_time_param<s>) const {
10        handler<s>();
11    }
12
13};
14
15_(cause 4) = [] { std::cout << "customization points effect 4\n"; };
16_(cause 5) = [] { std::cout << "customization points effect 5\n"; };
17
18
19int main() {
20    constexpr string_literal cause_1{ "cause 1" };
21    constexpr dispatcher<cause_1, "cause 2""cause 3"> dispatch;
22    dispatch.execute(cause_1);
23    dispatch.execute("cause 2");
24    dispatch.execute("cause 3");
25
26
27    const char cause_5[] = "cause 5";
28
29    dispatch.execute(compile_time_arg<cause_1>);   // OK
30    dispatch.execute(compile_time_arg<"cause 4">); // OK
31    dispatch.execute(compile_time_arg<cause_5>);   // Error
32}

这样虽然能够达到 O(1),但灵活性很差。因为实际的数据往往是程序运行之后才产生的,根本就不可能是编译期,所以毫无用武之地。
但是提供这么一个重载,也算是多了一种选择,它既能支持运算期,又能支持编译期。

CppMore
Dive deep into the C++ core, and discover more!
 最新文章