如何写一个简单的范围概念? [英] How to write a simple range concept?

查看:56
本文介绍了如何写一个简单的范围概念?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何编写一个概念来描述启用基于范围的 for 循环的类型?

How to write a concept that will describe the types the Range-based for loop is enabled for?

一种尝试是:

template < typename Range > concept bool RRange
    = requires(Range range) {{std::begin(range),std::end(range)};};

但我真正想要的是这样的东西:

but what I really want is some thing like this:

template < typename Range > concept bool RRange
    = requires(Range range) {{for(auto&& item : range);};}; // compile error

也就是说,RRange 是表达式 for(auto&& item : range); 对其有效的所有类型的概念.实现这一目标的最佳方法是什么?

that is, RRange to be the concept of all types the expression for(auto&& item : range); is valid for. What is the best way to achieve this?

我正在使用带有 g++ -std=c++1z -fconcepts 的 GCC7 快照.

I am using GCC7 snapshot with g++ -std=c++1z -fconcepts.

推荐答案

这是我在审查 [stmt.ranged] 时想到的.

Here's what I came up with while reviewing [stmt.ranged].

#include <utility>
#include <experimental/type_traits>

template <class T> using begin_non_mf_t = decltype(begin(std::declval<T>()));
template <class T> using begin_mf_t     = decltype(std::declval<T>().begin());
template <class T> using begin_t        = decltype(T::begin);
template <class T> using end_non_mf_t   = decltype(end(std::declval<T>()));
template <class T> using end_mf_t       = decltype(std::declval<T>().end());
template <class T> using end_t          = decltype(T::end);

template <class T>
constexpr bool has_member_begin_or_end {
    std::experimental::is_detected_v<begin_mf_t,T> ||
    std::experimental::is_detected_v<begin_t,T> ||
    std::experimental::is_detected_v<end_mf_t,T> ||
    std::experimental::is_detected_v<end_t,T>};

template <class T>
std::add_lvalue_reference_t<T>  declref() noexcept;
template <class T> using declref_t = decltype(declref<T>());

template <class T>
concept bool Range =
    requires /*Arrays*/ {
        requires std::is_array_v<T>;
        requires std::extent_v<T>!=0; // Extent is known.
    } ||
    /*Classes with member begin/end*/
    requires {
        requires std::is_class_v<T> && has_member_begin_or_end<T>;
    } &&
    requires (begin_mf_t<declref_t<T>> _begin,
                end_mf_t<declref_t<T>> _end) {
        { _begin!=_end } -> bool;
        { *_begin } -> auto&&;
        { ++_begin };
    } ||
    /*Types with non-member begin/end*/
    requires {
        requires !std::is_class_v<T> || !has_member_begin_or_end<T>;
    } &&
    requires (begin_non_mf_t<declref_t<T>> _begin,
                end_non_mf_t<declref_t<T>> _end) {
        { _begin!=_end } -> bool;
        { *_begin } -> auto&&;
        { ++_begin };
    };

还有测试用例.

#include <vector>

// Evaluates to true or diagnoses which constraints failed.
template <Range> constexpr bool is_range {true};

static_assert(!Range<void>);
static_assert(!Range<int>);
static_assert(!Range<int*>);
static_assert(!Range<int[]>);
static_assert(is_range<int[1]>);
static_assert(is_range<std::vector<int>>);

struct A { };
struct B {
    int begin;
};
struct C {
    int* begin();
    int* end();
};
struct D { };
struct E {
    int end;
};
enum F { };
struct G {
    int* begin() &&;
    int* end();
};
struct H {
    int* begin() &&;
    int* end() &&;
};
int* begin(D);
int* end(D);
int* begin(E);
int* end(E);
int* begin(F);
int* end(F);
int* begin(H);
int* end(H);

static_assert(!Range<A>);
static_assert(!Range<B>);
static_assert(is_range<C>);
static_assert(is_range<D>);
static_assert(!Range<E>);
static_assert(is_range<F>);
static_assert(!Range<G>);
static_assert(!Range<H>);

int main() { }

这篇关于如何写一个简单的范围概念?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆