C++20 概念:元素可迭代概念

C++20 Concepts: Element iterable concept

我正在尝试创建一个概念 ElementIterable,它可以确定类型是否为嵌套范围。例如,std::vector<int>中的元素是不可迭代的,但std::vector<std::vector<int>>中的元素(std::vector<int>)是可迭代的。想到用std::iterator_traits<T>,实验代码如下。但是,这个 ElementIterable 概念并不像预期的那样起作用。有没有解决这个 ElementIterable 概念的想法?

template<typename T>
concept ElementIterable = requires(typename std::iterator_traits<T>::value_type x)                        //  requires-expression
{
    x.begin();          // must have `x.begin()`
    x.end();            // and `x.end()`
};

这个ElementIterable的用法在这里

template<typename T> requires ElementIterable<T>
void Foo(T input);

template<typename T> requires ElementIterable<T>
void Foo(T input)
{
    std::cout << "Element iterable" << std::endl;
}

template<typename T>
void Foo(T input);

template<typename T>
void Foo(T input)
{
    std::cout << "Element not iterable" << std::endl;
}

函数的用法Foo.

int number = 1;
    
std::vector<decltype(number)> vector1;
vector1.push_back(number);
Foo(vector1);           //  Element not iterable

std::vector<decltype(vector1)> vector2;
vector2.push_back(vector1);
Foo(vector2);           //  Element not iterable
                        //      but expected behaviour is: Element iterable

欢迎所有建议。

C++20 概念可以像您需要的那样愚蠢(如文本替换)。在你的情况下,简单的模板鸭子类型应该通过检查你需要存在的东西来完成这项工作,即在你的类型的迭代器函数的结果中的迭代器函数。

考虑到这一点,您可以尝试这样的操作:

template<typename T>
concept ElementIterable = requires(T x)
{
    x.begin()->begin();        
    x.end()->end();            
};

嗯,问题是std::iterator_traits<T>iterator_traits 的参数应该是迭代器类型。同时,您希望该概念适用于容器。由于 std::iterator_traits 被设计为对 SFINAE 友好,并且容器不太可能满足足够的遗留迭代器概念,因此当您检查您的概念时,它很可能 std::iterator_traits<T> 没有成员。导致概念不满足。

为什么不依赖范围 header 中的概念?它有一个方便的实用程序来获取满足范围概念的类型的值类型

#include <ranges>

template<typename T>
concept ElementIterable = requires(std::ranges::range_value_t<T> x)
{
    x.begin();          // must have `x.begin()`
    x.end();            // and `x.end()`
};

或者,稍微更健壮并且没有重新发明标准特征

template<typename T>
concept ElementIterable = std::ranges::range<std::ranges::range_value_t<T>>;

如果你想问一个类型是否是一个本身包含范围的范围,那只是应用两次 std::range 类型:

template<typename T>
concept nested_range = std::ranges::range<T> && std::ranges::range<std::ranges::range_value_t<T>>

range_value_t 从范围的迭代器类型中提取 value_typeHere's a live example.