按类型或枚举调度执行策略?

Dispatch on execution policy by type or enum?

提问人:glades 提问时间:1/19/2023 更新时间:2/1/2023 访问量:196

问:

在 C++ 中,在基于策略的设计模式中,我基本上有两种选择:我可以使用单个类型(基于这些类型选择重载)或指定包含所有策略的枚举,并在运行时调度它们。如今,编写基于策略的设计的首选方式是什么?

演示

#include <cstdio>

/* Policy using types */

namespace type_policy
{
    struct detached_t{};
    struct deferred_t{};

    inline constexpr detached_t detached = detached_t{};
    inline constexpr deferred_t deferred = deferred_t{};
}

auto do_something(type_policy::detached_t pol)
{
    printf("detached type policy selected\n");
}

auto do_something(type_policy::deferred_t pol)
{
    printf("deferred type policy selected\n");
}

/* Policy using enums */

enum class enum_policy
{
    detached,
    deferred,
};

static auto do_something_else(const enum_policy pol)
{
    if (pol == enum_policy::deferred) {
        printf("deferred enum policy selected\n");
    } else {
        printf("detached enum policy selected\n");
    }
}

int main()
{
    do_something(type_policy::deferred);
    do_something_else(enum_policy::detached);
}

注意:当枚举调度内置到静态函数中时,编译器也能够在编译时消除条件。它从一开始就不那么冗长......这应该是首选方式吗?

C++ 重载 枚举类 基于策略的设计

评论


答:

1赞 cbuchart 2/1/2023 #1

通常,枚举是表达多个选项之一的自然方式,而不是使用更难理解的类似特征的机制,并迫使您为任何新选项生成新的重载。

关于最后一点,枚举的使用将通过更小、更清晰的界面简化对可用策略的更改。任何基于策略的函数 () 都将保留一个重载,而不是破坏 API 兼容性。do_something_else

最后,自 C++11 以来,与可以从任何整数隐式转换的类 C 类枚举相比,枚举类的使用提高了其安全性。

3赞 linuxfever 2/1/2023 #2

我会说这要看情况。您想让客户(包括您自己)能够轻松添加自己的新策略吗?如果是这样,基于类型的设计将允许他们添加新策略,而无需重新编译现有代码;他们所需要的只是:

namespace type_policy
{
    struct another_t {};
    inline constexpr another_t another = another_t{};
}

auto do_something(type_policy::another_t pol)
{
    printf("another type policy selected\n");
}

另一方面,基于枚举的设计只能由枚举所有者扩展。此外,如果更改枚举以添加新策略,则会强制客户端重新编译其代码,即使它们可能对刚刚添加的新策略不感兴趣。

话虽如此,基于类型的设计的缺点是策略最终可能分散在许多文件中,而不是基于枚举的,在枚举中,所有策略都很好地组合在枚举类中。

基于类型的设计的另一个缺点是它与运行时值一起使用稍微困难一些(因为您需要知道要传入的确切类型),而不是基于枚举的设计,在枚举中,从 int 到 的简单强制转换就可以了。do_somethingenum_policy