Concepts-Lite iterator comparison 比较值

Concepts-Lite iterator comparison compares values

几个月来,我一直在为这个问题绞尽脑汁。我已经定义了一组松散地描述容器和谓词的概念。

一般来说,我使用老式的 for 循环遍历容器,并将参数迭代器与 end(container) 迭代器的相等性进行比较。我想不通的是为什么在给定 Container<T> 时无法编译,使得 T 没有相等比较器 (T::operator==(T other))

这些概念绝不是完整的,只是为了学习目的,毫无疑问还有其他方法可以完成我正在做的事情。

问题代码在"queryalgorithms.h"中定义的这个短函数中:

#pragma once

#include <algorithm>
#include "concepts.h"

template<typename C, typename P, typename V = typename C::value_type, typename I = typename C::iterator>
I last(C & collection, I iterator, P predicate) requires Container<C> && Predicate<P, V> && Incrementable<I> {
    I out;
    for (iterator; iterator != end(collection); iterator++) {
    }

    return out;
}

失败的测试代码在这里:

#include <iostream>
#include <vector>
#include <algorithm>
#include <forward_list>

#include "queryalgorithms.h"

using namespace std;

class MyClass {
    public:
        int value;

        MyClass(int v): value(v) {};
};

template <typename T>
void Test() {
    auto collection = T();
    for (auto i = 0; i < 10; i++)
        last(collection, begin(collection), [] (auto x) { return true; });
}

int main(int argc, char * argv[]) {
    Test<vector<MyClass>>();
    return 0;
}

不确定这是否有帮助,但为了完整起见,concepts.h 文件是 here。很多,我觉得它没有增加太多价值,所以我把它放在 pastebin 上。

如上所述,这个小示例仅针对定义了相等比较器的类型进行编译(例如 Test<vector<int>>() 可以正常工作)。 g++ 的编译器错误如下:

/usr/include/c++/6.3.1/bits/stl_algobase.h:800:22: error: no match 
for ‘operator==’ (operand types are ‘const MyClass’ and ‘const MyClass’)
  if (!(*__first1 == *__first2))

所以我的问题是,为什么编译器将 iterator != end(collection) 的类型推断为值类型 V 而不是迭代器类型 I

编辑:我正在使用g++ -fconcepts --std=c++17 -o test test.cc

进行编译

Container<T> 需要 EqualityComparable<T>,这需要 a == b 左值 ab 类型 T。 C++ 标准规定容器的 a == b 要求其值类型为 EqualityComparable (N4659 [container.requirements.general] Table 83)。 在 last 的 require 子句中检查 Container<vector<MyClass>> 实例化 vector== 运算符,这很可能是根据 std::equal 实现的,我推测是算法在 stl_algobase.h.

的第 800 行定义

因为 MyClass 不是 EqualityComparable,所以 vector<MyClass> 不是模型 Container。值得注意的是,该标准不需要 vector(或任何容器的)operator== 受到约束,因此您会在检查约束时遇到硬错误,而不是 last SFINAE-ing 并删除自身来自重载决议。