为什么 C++ 标准库更喜欢模板而不是枚举?

Why does the C++ standard library prefer templates over enums?

提问人:Post Self 提问时间:11/24/2022 最后编辑:Post Self 更新时间:11/24/2022 访问量:123

问:

根据 https://en.cppreference.com/w/cpp/algorithm/execution_policy_tag,namespace 定义了各个类型的编译时常量:std::execution

inline constexpr std::execution::sequenced_policy seq { /* unspecified */ };
inline constexpr std::execution::parallel_policy par { /* unspecified */ };
inline constexpr std::execution::parallel_unsequenced_policy par_unseq { /* unspecified */ };
inline constexpr std::execution::unsequenced_policy unseq { /* unspecified */ };

这些值用于参数化其他函数以使用不同的模式。

此目的另一种实现可能如下所示:

enum class policy {
    seq,
    par,
    par_unseq,
    unseq,
};

我可能会看到前者比后者有两个好处,但两者都不成立:

  1. 您可以根据此参数定义函数的单个重载;然而,这在实践中并不是这样做的:有std::for_eachtemplate<typename ExecutionPolicy, ...>
  2. 它是可扩展的:用户不能扩展枚举,但用户始终可以定义自己的结构,这通常在整个标准库中是允许的,例如,通过模板专用化;但是,这不适用于此处,因为标准库未指定实现细节;因此,无法创建自己的符合标准的类型

标准库方法的主要缺点是它将使用函数转换为模板,从而使所有内容内联、编译速度变慢等。

当枚举也可以完成这项工作时,对枚举使用单独的类型的原因是什么?标准库中是否有任何预定义枚举的示例?

在编写我自己的库时,我应该模仿这个约定还是在可能的情况下选择枚举?

C++ 模板 枚举 c++-standard-library

评论

3赞 273K 11/24/2022
不同类型的重载解析,枚举不参与。
2赞 273K 11/24/2022
template<policy_enum ExecutionPolicy> void f{}非类型化模板不会推导模板参数值。
3赞 Evg 11/24/2022
使用函数参数,您必须为函数内枚举值的运行时检查付费。使用 tag 函数参数,将在编译时选择一个函数。如果您需要运行时灵活性,则可以在编译时标记之上自己完成。如果你不想付钱,你别无选择。是的,我们在标准库中确实有枚举。enumenum
1赞 lorro 11/24/2022
@PostSelf 假设你有 and 在参数(或类似的东西)中,那么你可以做 ,或类似的事情(请原谅任何错别字,这是一个评论框 - 可以在一个不同的问题中给出更精美的答案)。template<typename... Ts>std::tuple<Ts...> tpl[&]<size_t... is>(std::index_sequence<is...>) { return ([&](auto arg) { /* do something with arg, return true to continue */ }(std::get<is>(tpl)) && ...); }(std::make_index_sequence<sizeof...(Ts)>());
2赞 Pete Becker 11/24/2022
并行算法的非并行版本是模板,因此将并行策略参数定义为不同类型不会“将消费函数转换为模板”。

答:

2赞 user17732522 11/24/2022 #1

无论如何,标准库算法都是模板,因此在这方面没有任何差异。

将枚举方法与所有共享相同类型的策略一起使用的唯一好处是,可以在运行时轻松选择策略。但是,策略的选择必须与所使用的类型/算法相协调。这不太可能有用。

在其他条件相同的情况下,最好对每个策略使用不同的类型,以便在编译时提供更多信息。如果需要,始终可以在实现中丢弃编译时信息,但反之则不可能。

关于您的积分:

  1. 仅仅因为标准只指定了一个重载并不意味着实现必须只使用一个重载。允许标准库实现使用任意数量的重载。

  2. 无论如何,都不允许专用化或重载标准库函数。

评论

0赞 Post Self 11/24/2022
谢谢,这些观点是有道理的。关于运行时选择的想法很有趣,因此我将为我自己的库选择枚举。注意:您可以在命名空间中专门化模板:en.cppreference.com/w/cpp/language/extending_stdstd
0赞 user17732522 11/24/2022
@PostSelf (通常)允许对模板进行专业化。专用函数模板则不然。