【问题标题】:Concepts-Lite iterator comparison compares valuesConcepts-Lite 迭代器比较比较值
【发布时间】:2017-05-12 19:42:52
【问题描述】:

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

一般来说,我使用老式的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&lt;vector&lt;int&gt;&gt;() 可以正常工作)。来自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进行编译

【问题讨论】:

    标签: c++ c++11 c++-concepts


    【解决方案1】:

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

    由于MyClass 不是EqualityComparablevector&lt;MyClass&gt; 不代表Container。值得注意的是,该标准不要求 vector(或任何容器的)operator== 受到约束,因此您会遇到硬错误检查约束而不是 last SFINAE-ing 并从重载解决方案中删除自身。

    【讨论】:

    • 诚然,我把Container&lt;T&gt; 的定义弄乱了你引用的标准,所以谢谢你。我对Container&lt;T&gt; 的定义(注意它是自定义定义)要求Container&lt;T&gt; 本身为EqualityComparable 而不是Container::value_type。正如您在答案中指定的那样,将Container 调整为EqualityComparable 的正确定义会留下更短的错误。但是,我不认为这回答了原来的问题
    • 将此子句更改:“last 上的 requires 子句实例化向量的赋值运算符...”为“...实例化向量的相等运算符..”,我会接受这个答案。问题是由于我对 ContainerEqualityComparable 定义混乱,而不是它的值类型。谢谢
    • 哎呀,好主意。