代码之家  ›  专栏  ›  技术社区  ›  Drag-On

如何使用按值解引用运算符编写C++23常量_范围工厂

  •  0
  • Drag-On  · 技术社区  · 2 年前

    我编写了一个与iota非常相似的范围工厂,但生成用户定义类型的实例。简介如下:

    struct MyType;
    
    struct MyIterator {
        using value_type = MyType;
        using iterator_concept  = std::input_iterator_tag;
        // ...
        auto operator*() const -> MyType;
    };
    
    struct MyView : public std::ranges::view_interface<MyView> {
        auto begin() const -> MyIterator;
        auto end() const -> MyIterator;
    };
    

    我已经尽了最大努力让这个遵循iota_view的设计。然而,我发现 MyView 不是一个恒定范围:

    static_assert( std::ranges::constant_range<std::ranges::iota_view<int>>);
    static_assert(!std::ranges::constant_range<MyView>); // Not a constant_range!
    

    看了之后 the reference ,我追溯到 MyIterator 不是 constant-iterator 因为

    • std::same_as<std::iter_const_reference_t<MyIterator>, std::iter_reference_t<MyIterator>> 不成立是因为
    • std::iter_reference_t<MyIterator> MyType 但是 std::iter_const_reference_t<MyIterator> const MyType .

    如果我更换 MyType 具有 int ,就像 iota_view ,则两者都是非常量。

    所以我想弄清楚区别是从哪里来的,结果发现 std::iter_const_reference_t 定义为 std::common_reference_t ,已被广泛覆盖 here 。反过来,它有一个复杂的策略来计算结果类型,但实际上两者都有 int MyType 属于同一分支,即(参见 cppreference ):

    template<class T> T val();
    decltype(false? val<const T&&>() : val<T>())
    

    事实证明这是 int 如果 T int const MyType 如果 T MyType .

    我不知道为什么条件运算符解析这样的类型,但无论如何我都无法更改它;但幸运的是,该标准允许我通过专门化来注入自己的行为 std::basic_common_reference ,例如,我可以这样做:

    template<template<class> class TQual, template<class> class UQual>
    struct std::basic_common_reference<MyType, MyType, TQual, UQual>
    {
        using type = std::common_type_t<TQual<MyType>, UQual<MyType>>;
    };
    

    事实上,这解决了这个问题。但我不知道这是否正确,甚至不知道是否打算这样使用。一般来说,这似乎不太实用,因为没有具体的范围 MyType -它恰好是我正在生成的类型,在我的真实用例中,它是视图的模板参数。这意味着视图是否符合constant_view完全取决于它所模板化的类型是否具有此basic_common_reference专门化。。。这似乎很奇怪。

    供您参考,这里有 godbolt 链接

    最后,这里有一个问题:用左值引用类型实现constant_view的正确方法是什么?感谢您的真知灼见。

    0 回复  |  直到 2 年前
        1
  •  1
  •   康桓瑋    2 年前

    最简单的方法是返回一个常量 MyType 对象

    struct MyIterator {
        // ...
        auto operator*() const -> const MyType;
    };
    
    static_assert(std::ranges::constant_range<MyView>);
    
    推荐文章