对容器命名要求的澄清

A clarification on the named requirements for containers

我正在努力掌握容器 类 的 (C++20) 标准要求的细节,以期编写一些与标准兼容的容器 类图书馆。为了开始研究这个问题,我查阅了 命名要求 的参考资料,特别是关于容器要求的参考资料,并且只找到了一个 general container requirement 称为 Container 的参考资料标准。阅读此要求给出了我不确定的两个问题,并希望得到一些澄清:

  1. 两个容器类型C的表达式a == b的要求以元素类型T为前提,即它是相等可比较的。但是,稍后在同一页面上 header 'other requirements' 下明确要求 T 始终相等可比较。因此,根据我的阅读,上述要求的先决条件是多余的,不需要给出。我的这种想法是否正确,或者我应该考虑其他因素吗?

  2. 我很惊讶地看到 T 的明确要求:特别是上面的相等可比较要求和可破坏的命名要求。这是否意味着构造不满足这些要求的类型的标准容器或仅对它们执行某些标准库函数调用是未定义的行为?

抱歉,如果这两个问题听起来很愚蠢,我目前正在尝试将我的 C++ 知识从对如何使用功能有基本了解的地方转变为稳健的理解,以便我可以编写好的通用代码。虽然我正在尝试使用标准(草案)来尽可能地查找行为,但它的措辞往往过于冗长,以至于我无法完全理解实际所说的内容。


为了寻求答案,我编写了一个快速测试 .cpp 文件来尝试编译,如下所示。所有未注释的代码均使用设置为 C++20 的 MSVC 编译器进行编译。所有注释的代码都不会编译,反之亦然,所有未注释的代码都会编译。似乎一个人天真地认为应该起作用的东西特别是:

但是,仅仅因为我的编译器允许我在 T 不是 equality-comparable 的情况下生成 vector<T> 的 object 并不意味着我已经实现了符合标准的行为/所有我们的行为并非未定义 - 这是我想要关注的,尤其是至少违反了容器 object 的一些常见要求。

代码:

#include<vector>
#include<iostream>

//A basic class with its == operator removed
class MyNonEqualityComparableClass
{
    //Destroy any possible == operator, for good measure
    template<typename T>
    auto operator==(T&& t) = delete;

    public:
        //Give the test struct a value so we mute the class and check
        bool Mytestvalue = true;
};

class MyNonDestructableClass
{
    ~MyNonDestructableClass() = delete;
};



// A basic class template with no functionality added
template<typename T>
class MyTemplateClass 
{};

int main()
{


//1. Non-destructable Class Test.
{
    
    //Compiler Grumbles if uncommented, no destructor is inaccessable for the class
    //MyNonDestructableClass a, b;

    //Class Dependent On my Nondestructable Class
    MyTemplateClass < MyNonDestructableClass> mtc;

    //Compiler Grumbles if uncommented, as class tries to acceess the inacessable destructor of MyNonDestructableClass
    //auto u = std::vector< MyNonDestructableClass>();

    
}

//2. Non-Equality-Comparable Class Test.
{
    
    MyNonEqualityComparableClass x, y;
    //Compiler Grumbles if uncommented 
    //x == y;

    //Compiler Fine with below
    auto u = std::vector<MyNonEqualityComparableClass>();
    auto v = std::vector<MyNonEqualityComparableClass>();
    u.push_back(x);
    v.push_back(y);
    x.Mytestvalue = !x.Mytestvalue;

    //Compiler Grumbles if uncommented 
    //u == v;

    std::cout << "The value of x.Mytestvalue is: \t" << std::boolalpha << x.Mytestvalue << std::endl;
}

}

我的输出:

The value of x.Mytestvalue is:  false

如果一个容器的成员是不可破坏的,那么这个容器除了添加新元素(或替换现有元素)之外什么也做不了。 eraseresize和销毁都涉及销毁元素。如果你有一个不可破坏的类型 T,并试图实例化一个 vector<T>(比如说),我预计它会编译失败。

至于重复的需求,我怀疑这只是 CppReference 人员编写该页面时偷偷摸摸的东西。标准中的容器要求(在 a == b 的条目中)提到元素必须相等且可比较。

这里的原始问题提问者通过阅读标准草案 (N3797) 提供了我接受的答案的一些补充信息。根据容器要求,T 相等可比较的要求只是容器 a==b 的前提条件。请注意, 没有 明确提到要求 T 在该条件之外的任何地方都具有可比性,以使容器符合标准。这与 Cpp 参考网站进行了比较,该网站将相等性放在容器命名要求的标题 other requirements 下。 (让我相信,拥有 object 不满足平等可构造或可破坏要求的容器是符合标准的行为)。请注意,可破坏的命名要求是 object 在销毁时释放其所有资源的语义要求,而不仅仅是粗略阅读我的问题可能暗示的析构函数。

因此,我现在假设在容器要求中包含 T 是相等的可比性要么是 Cpp 参考网站的错误,要么 header 其他要求具有 'other requirements related to this named requirement you may need reference to' 而不是“这些是对容器的额外要求”。无论哪种方式,网站上都不清楚是什么意思,还是其他意思。