【问题标题】:C++20 Concepts: Element iterable conceptC++20 概念:元素可迭代概念
【发布时间】:2020-10-21 15:13:46
【问题描述】:

我正在尝试创建一个概念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

欢迎所有建议。

【问题讨论】:

  • 为什么不简单地检查类型本身的v.begin()-&gt;begin()v.end()-&gt;end() T

标签: c++ c++20 c++-concepts


【解决方案1】:

如果你想问一个类型是否是一个本身包含一个范围的范围,那就简单地应用两次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.

【讨论】:

    【解决方案2】:

    好吧,问题是std::iterator_traits&lt;T&gt;iterator_traits 的参数应该是迭代器类型。同时,您希望该概念适用于容器。由于std::iterator_traits 被设计为对 SFINAE 友好,并且容器不太可能满足遗留迭代器概念,所以当您检查您的概念时,std::iterator_traits&lt;T&gt; 很可能没有成员。这导致概念不满足。

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

    #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::iterator_traits&lt;T&gt;无法生效的原因解释。
    【解决方案3】:

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

    考虑到这一点,您可以尝试以下方法:

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

    【讨论】:

    • 是的,修复了它,是复制提供的代码后遗留下来的
    • 这是一个非常糟糕的概念。它不使用任何现有的标准库概念,因此不能包含它们。它只检查 memberwise begin/end 的存在,而不是允许其他事情的 ranges::begin/end。总的来说,这不是解决问题的好方法。
    猜你喜欢
    • 2021-03-04
    • 1970-01-01
    • 2020-09-28
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多