我試圖std::optional通過制作一個只針對一件事然后中斷的迭代器來制作一個范圍:
#include<ranges>
#include <iostream>
#include<optional>
namespace maybe {
template<class T>
class iterator_to_nowhere
{
public:
using difference_type = ptrdiff_t;
using value_type = T;
using reference = T&;
using pointer = T*;
using interator_category = std::forward_iterator_tag;
iterator_to_nowhere(iterator_to_nowhere<T> const& other) = default;
iterator_to_nowhere(T* p) : ptr(p) {};
~iterator_to_nowhere() = default;
iterator_to_nowhere<T>& operator=(const iterator_to_nowhere<T>&) = default;
iterator_to_nowhere<T>& operator () { invalidate(); return *this; }
iterator_to_nowhere<T> operator (int) { auto temp = *this; invalidate(); return temp; }
reference operator*() { return *ptr; }
T operator*() const { return *ptr; }
pointer operator->() const { return ptr; }
friend bool operator==(iterator_to_nowhere const& lhs, iterator_to_nowhere const& rhs) = default;
friend bool operator!=(iterator_to_nowhere const&, iterator_to_nowhere const&) = default;
friend void swap(iterator_to_nowhere<T>& lhs, iterator_to_nowhere<T>& rhs) { std::swap(lhs, rhs); }
private:
void invalidate() { ptr = nullptr; };
T* ptr;
};
...然后在派生類上使用該迭代器實作范圍事物std::optional
template<class T>
class optional : public std::optional<T>
{
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using iterator = iterator_to_nowhere<T>;
using const_iterator = iterator_to_nowhere<T const>;
using sentinel = iterator;
public:
optional() = default;
optional(optional<T> const&) = default;
optional(optional<T>&&) = default;
optional(std::optional<T> const& val) : std::optional<T>(val) {};
optional(std::nullopt_t const& nullopt) : std::optional<T>(nullopt) {};
optional(T const& val) : std::optional<T>(val) {};
iterator begin() { return { raw() }; }
const_iterator cbegin() { return { raw() }; }
iterator end() { return { nullptr }; }
const_iterator cend() { return { nullptr }; }
size_t size() const { return size_t(this->has_value()); };
private:
T* raw() { return (this->has_value()) ? (&(this->operator*())) : nullptr; }
};
}
然后我在以下函式中運行它:
int main()
{
maybe::optional<int> just3(3);
for (int three : just3)
std::cout << three ; //prints "3";
auto adaptor = std::views::transform([](int n) {return n * 2;});
//auto six_range = just3 | adaptor; //Error C2678 binary '|': no operator found which takes a left - hand operand of type 'maybe::optional<int>' (or there is no acceptable conversion)
}
在標準設定為 /std:c latest 的 VS2019 中構建,它在基于范圍的回圈中運行良好,但當我嘗試將其通過管道傳輸到配接器時會產生給定的錯誤。有什么我需要實施的嗎?
uj5u.com熱心網友回復:
檢查您的范圍是否是有效的 C 20 范圍的最佳方法是檢查您的迭代器是否是有效的 C 20 迭代器:
static_assert(std::forward_iterator<maybe::iterator_to_nowhere<int>>);
當你這樣做時,你會看到這個要求失敗了:
/opt/compiler-explorer/gcc-trunk-20221020/include/c /13.0.0/bits/iterator_concepts.h:538:18: note: nested requirement 'same_as<std::iter_reference_t<const _In>, std::iter_reference_t<_Tp> >' is not satisfied
538 | requires same_as<iter_reference_t<const _In>,
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
539 | iter_reference_t<_In>>;
| ~~~~~~~~~~~~~~~~~~~~~~
因為你有:
reference operator*() { return *ptr; }
T operator*() const { return *ptr; }
這些回傳不同的型別(referenceis T&)。回傳T&是正確的,但運算子需要是const. 所以:
reference operator*() const { return *ptr; }
一旦我們解決了這個問題,我們就有了一個有效的輸入迭代器。但是對于前向迭代器,我們還需要默認構造(這也是哨兵所必需的)。
修復了這兩個問題,我們現在有了一個有效的范圍和transform作品。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/519911.html
標籤:C 模板c 20
