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

Jim*_*yHu 5 c++ c++-concepts c++20

我正在尝试创建一个ElementIterable可以确定类型是否为嵌套范围的概念。例如,in 中的元素std::vector<int>不可迭代,但std::vector<int>in 中的元素 ( )std::vector<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()`
};
Run Code Online (Sandbox Code Playgroud)

这个的用法ElementIterable是here。

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;
}
Run Code Online (Sandbox Code Playgroud)

函数的用法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
Run Code Online (Sandbox Code Playgroud)

欢迎提出所有建议。

Sto*_*ica 7

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

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

#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()`
};
Run Code Online (Sandbox Code Playgroud)

或者,稍微更强大并且无需重新发明标准特征

template<typename T>
concept ElementIterable = std::ranges::range<std::ranges::range_value_t<T>>;
Run Code Online (Sandbox Code Playgroud)


Nic*_*las 7

如果你想询问一个类型是否是一个本身包含一个范围的范围,那就是简单地应用该std::range类型两次:

template<typename T>
concept nested_range = std::ranges::range<T> && std::ranges::range<std::ranges::range_value_t<T>>
Run Code Online (Sandbox Code Playgroud)

range_value_tvalue_type从范围的迭代器类型中提取。这是一个活生生的例子


Bli*_*ndy 5

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

考虑到这一点,您可以尝试这样的事情:

template<typename T>
concept ElementIterable = requires(T x)
{
    x.begin()->begin();        
    x.end()->end();            
};
Run Code Online (Sandbox Code Playgroud)

  • 这是一个非常糟糕的概念。它不使用任何现有的标准库概念,因此无法包含它们。它检查的只是 *memberwise* `begin/end` 的存在,而不是允许其他事情的 `ranges::begin/end` 的存在。总的来说,这并不是解决问题的好方法。 (3认同)