在 C++ 中使用 enum 代替 struct 进行标签调度

问题描述 投票:0回答:2

让我们从标准库中实现

std::unique_lock

struct defer_lock_t { explicit defer_lock_t() = default; };
struct try_to_lock_t { explicit try_to_lock_t() = default; };
struct adopt_lock_t { explicit adopt_lock_t() = default; };

inline constexpr defer_lock_t  defer_lock {};
inline constexpr try_to_lock_t try_to_lock {};
inline constexpr adopt_lock_t  adopt_lock {};

unique_lock (mutex_type& m, defer_lock_t t) noexcept;
unique_lock (mutex_type& m, try_to_lock_t t);
unique_lock (mutex_type& m, adopt_lock_t t);

是否有理由不/不能/不应该使用枚举而不是结构来实现标签调度?如:

enum defer_lock_t { defer_lock };
enum try_to_lock_t { try_to_lock };
enum adopt_lock_t { adopt_lock };

unique_lock (mutex_type& m, defer_lock_t t) noexcept;
unique_lock (mutex_type& m, try_to_lock_t t);
unique_lock (mutex_type& m, adopt_lock_t t);

后者更简洁。

我能想到的使用结构的唯一优点是继承(例如,迭代器标签)。但在所有其他情况下,为什么不使用枚举呢?

c++ c++17 language-design unique-lock tag-dispatching
2个回答
14
投票

首先,您不希望标签类型是可构造的,您想明确地命名它们。这并不特别适用于

{}
,因为
unique_lock
会不明确,但有一个一般原则。标签类型的设计使得您必须编写
unique_lock<std::mutex> lk(m, {})
(或者,如果您确实想要,
std::defer_lock
)。

其次,您实际上只想在要使用标签类型的特定上下文中使用它们。如果你将它们设为

std::defer_lock_t()

,那么你就引入了所有

enum
功能 - 比如可转换为整数:

enum

这些其他表达式没有任何意义,所以最好不要它们存在。 

第三,在只有少量固定字符的情况下,实现标准库的简洁性并不是一个大问题。所以我什至不认为

std::make_unique<int>(std::defer_lock); // ok? // is this like super deferred? auto x = std::defer_lock * 2; // what do you get when you multiply six by nine? std::unique_lock lk(m, static_cast<std::defer_lock_t>(42));

的实施是一个胜利。标准库中的标签类型并不多。

    
除了 Barry 列出的原因之外,另一个(次要)好处是,如果函数调用不是内联的,则枚举标记具有需要传递到函数中的状态,而结构标记则不需要。即使看起来枚举是空的,无作用域枚举始终具有至少一个可以转换到其中的状态字节,而作用域枚举始终具有至少一位状态。请参阅

http://eel.is/c++draft/enum#dcl.enum-7

3
投票

给定 enum

用于 64 位 Linux 的 clang 和 gcc 都会生成

struct s {};
enum e {};

void a(s);
void b(e);

void c() {
    a(s());
}

void d() {
    b(e());
}

但请注意,在 Windows 上,调用约定似乎阻止了这种情况(MSVC 代码生成):

c():                                  # @c()
        jmp     a(s)                          # TAILCALL
d():                                  # @d()
        xor     edi, edi
        jmp     b(e)                          # TAILCALL

观看直播:

https://godbolt.org/z/ss7Ke64ca

    

© www.soinside.com 2019 - 2024. All rights reserved.