IEEE是否为std :: map和std :: set浮动有效的键类型?

eta*_*ion 21 c++ map set ieee-754

背景

对关键容器的键类型(例如std :: map)的比较器的要求是它对键类型的元素施加严格的弱顺序.

对于给定的比较器,comp(x, y)我们定义equiv(x, y) = !comp(x, y) && !comp(y, x).严格弱势秩序
的要求comp(x, y)

  1. 不可反复性(!comp(x, x)适合所有人x)
  2. 排序的传递(如果comp(a, b)comp(b, c)comp(a, c)).
  3. 等价的传递性(如果equiv(a, b)equiv(b, c)然后equiv(a, c))

std::less<float>(默认比较器)使用operator<,因为没有创建严格的弱顺序NaN.由于x < NaNNaN < x是全是假的x,NaN就相当于这个比较下的所有花车,这打破条件#3:equiv(1.0, NaN)equiv(NaN, 2.0),但不会equiv(1.0, 2.0).对于除NaN之外的IEEE浮点数,它是一个严格的弱顺序(其中每个数字都有自己的等价类,除了0-0).

这个问题

这是否意味着C++标准不允许使用IEEE浮点数(和(长)双精度数)作为关联容器中的键类型,因为上述问题,即使我确保NaN永远不会插入到容器中?我不太确定Key标准中的"元素"措辞 - 如果它意味着所有可能的元素或仅仅是最终在容器中的元素.

注意:问题不在于问题.截断/舍入,我很快就会发布一个不同的问题.

更新:

叹了口气.我应该在没有指定浮点数的情况下提出问题,我只是觉得这是一个很好的例子.

真正的问题是:是否允许使用比较器,该比较器仅对放入容器的元素施加严格的弱顺序,而不是所有可能的密钥类型实例?请不要只回答"是"或"否",我想参考标准/事先讨论此事/来自委员会成员的回答.

Ste*_*sop 9

我怀疑这些限制应该被视为关系在实际用作键的值上的行为,而不一定是所有类型的值.目前没有时间通过​​标准寻找引用实际容器元素的"吸烟枪"语言而不是所有类型的值.

类似的情况:如果一个比较器(用于指针或智能指针的容器)调用一个虚函数,并且有人链接它所比较的​​类型的派生类,它会以一种使比较器不是严格弱的方式覆盖虚函数订购?即使没有人真正使用该派生类,该程序是否也未定义?

如果有疑问,你可以使用一个严格弱的比较器来支持NaN:

bool operator()(double a, double b) {
    if ((a == a) && (b == b)) {
        return a < b;
    }
    if ((a != a) && (b != b)) return false;
    // We have one NaN and one non-NaN.
    // Let's say NaN is less than everything
    return (a != a)
}
Run Code Online (Sandbox Code Playgroud)

最后两行"优化" return (b == b);,虽然我不确定评论是否会优化.

我认为Tomalak已经说服我语言确实说需要订购整个类型.

这没什么意义,因为地图不会冒出任何值,它只使用它给出的值(以及它们的副本),但问题是关于规则,据我所知它们是规则.C++ 0x是一样的.我想知道是否存在缺陷报告或提交缺陷报告.

这也是对(很少见)系统中的那恼人的std::less是指针慢,您不能使用<在地图上指针的比较,即使你知道指针均为同一个数组的元素.耻辱.

另一个选项是使用以下类作为键类型,因此仅在进入地图时检查键的NaN,而不是如上所述的每个比较.

struct SaneDouble {
    double value;
    SaneDouble (double d) : value(d) {
        if (d != d) throw std::logic_error();
    }
    static friend bool operator<(SaneDouble lhs, SaneDouble rhs) {
        return lhs.value < rhs.value;
    }
    // possibly a conversion to double
};
Run Code Online (Sandbox Code Playgroud)

这提出了另一个问题 - 显然有人可以创建一个SaneDouble然后将其设置value为NaN(假设实现允许它们从某个地方获得一个而不会崩溃).那么"SaneDouble的元素"是否严格弱有序?我在构造函数中创建类不变量的半心半意的尝试是否使我的程序未定义,即使没有人真正打破不变量,只是因为它们可以,因此这样做的结果是"SaneDouble的元素"?是否真的是标准的意图,当且仅当value标记时才定义程序的行为private?标准是否实际定义了某种类型的"元素"在哪里?

我想知道我们是否应该解释"Key的元素"来表示比较器对Key的某些元素产生严格的弱序.大概包括实际使用的那些."我有甜甜圈"并不意味着我有每个甜甜圈.不过,这是一段时间.