C++中的标准或惯用空对象
我经常需要在 C++ 中定义一个空对象,它通常是一个没有任何成员或方法的结构:
struct Dummy {};
同样的想法的化身包括类喜欢nill_t,null_t,Empty,None等。
我想知道是否有符合此描述的标准库对象(空类,用作“无”或“空”的标记)或定义它的规范方式(专有名称等)。一个想法是使用,std::false_type但不幸的是这个类远非空的。
编辑:
理想情况下,我会使用 Standard None 类型作为(n 空)基础来拥有丰富的名称描述和隐藏实现(或按原样使用,在有意义的地方)
struct Dummy : std::none {};
struct Noop : std::none {};
让语言处理复杂的“无”,就像@Barry 在他的回答中提到的那样,或者例如提供一个总是返回的相等运算符false(如 NaN)或任何语言认为“无”的“正确行为”都会很好.
问题只是询问是否有标准的 None 或 Empty 或 Nothing 类型,我从不建议通过在没有意义的地方使用它来混淆代码。
回答
C++ 标准库实际上有大量的“空”类型。std::monostate、std::nullopt_t、std::in_place_t标签类型等。它们都有不同的名称,因为它们用于不同的目的。
你不应该有一种通用的“空”类型,因为看到那里的名字会告诉你代码在做什么。std::optional<T>(std::in_place, ...)传达更多关于正在发生的事情而不是std::optional<T>(std::monostate{}, ...).
事实上,如果使用单一类型,您将无法区分std::optional<T>(std::nullopt)和std::optional<T>(std::in_place)。这是两个非常不同的函数调用。
您使用的名称应该是使使用它的代码可读的任何名称。
至于规范约定,C++ 标准根据您的使用方式使用某些约定。用户希望直接输入到他们的代码中的类型,如std::monostate,通常命名。您应该创建在类型variant中使用的 s monostate。
用于选择构造函数或operator()重载的标记类型通常以_t. 但是它们也inline constexpr为它们定义了一个不以_t. 例如,std::nullopt_t是类型的名称,而std::nullopt是该类型的变量的名称。
这一点特别重要,因为std::nullopt_t's 不能由用户直接构造。您可以复制std::nullopt实例,但不能std::nullopt_t直接创建实例。
最后一点是标准有点不一致的地方。大多数标签类型没有这个要求;你可以调用std::in_place_t{}所有你喜欢的。但std::nullopt_t确实如此。
您评论中的示例:
作为结构模板中的默认标签,作为函数模板中的默认标签
我不知道在这种情况下什么是“默认标签”,但我可能会称之为default_t. 因为这说明了事物的含义。
作为处理管道中的“无输出”标签
我会拼写这个,void或者如果那不是一个选项,drop或者discard.
在一些通用代码中相当于 Python 的 None
那已经有一个名字:nullptr。如果它是一个可能存在也可能不存在的非指针,则拼写为std::optional<T>。如果您真的使用通用代码,则std::nullopt它本身可以作为一种方式来指示用户在概念上提供了一个空的optional.
这些是具有不同解释含义的不同用途。因此,即使它们都实现为等效类型,它们也不应该具有相同的名称。
回答
最好的做法是这样做:
struct Dummy { explicit Dummy() = default; };
然后你可以创建一个实例:
inline constexpr Dummy dummy;
这样做的优点是它Dummy不是聚合(在 C++20 中),这会阻止编译:
void f(Dummy);
f({}); // error
f(Dummy{}); // ok
f(dummy); // ok
这很重要,因为标签类型的重点是可见性,而{}不是……不是。
我想知道是否有符合此描述的标准库对象
有很多标准库的空标签类型(例如std::nullopt_t),但是如果您需要一个标签类型,那么您出于特定原因需要它,并且为了避免创建新类型而重用现有标签似乎不是一个好的权衡。我的意思是,std::nullopt_t如果这对您正在做的事情有意义,请使用(也许您正在做的事情optional与此相当,因此这是用于解决此问题的合理标签)但不要仅仅使用std::nullopt_t因为...您需要一个标签和这是可用的。