By Gašper Ažman
27.2.3 Input Iterators:
Expression | Return type | Semantics |
---|---|---|
*r | convertible to T | |
*r++ | convertible to T | { T tmp = *r; ++r; return tmp; } |
(well technically it's derived from std::false_type, but close enough)
is_convertible<unique_ptr<int>&, unique_ptr<int>>{}?
error: requirement
Convertible(unique_ptr<int>&, unique_ptr<int>)
not satisfied.
required by InputIterator(vector<unique_ptr<int>>::iterator)
required by ForwardIterator(vector<unique_ptr<int>>::iterator)
required by BidirectionalIterator(vector<unique_ptr<int>>::iterator)
required by RandomAccessIterator(vector<unique_ptr<int>>::iterator)
vector<unique_ptr<int>> v;
v.push_back(make_unique(5));
for_each(v.begin(), v.end(), [](auto&) {});
T& | T const& | T | T&& | proxy
T& is not convertible to T for move-only types.
AKA vector<unique_ptr>::iterator
T& | T const& | T | T&& | proxy
AKA vector<unique_ptr>::const_iterator
T& | T const& | T | T&& | proxy
... with the caveat that:
- there are no such iterators (yet)
- they would move the original values out
T& | T const& | T | T&& | proxy
FOR REAL
AKA move_iterator<vector<unique_ptr>::iterator>
But remember *r++?
{ T tmp = *r;
++r;
return tmp; }
The operational semantics ALWAYS MOVE!
even if you're discarding the value.
T& | T const& | T | T&& | proxy
AKA vector<unique_ptr>{} | filter{predicate}
But remember *r++?
{ T tmp = *r;
++r;
return tmp; }
SAME PROBLEM... Maybe. Or plain doesn't work.
27.2.3 Input Iterators:
Expression | Return type | Semantics |
---|---|---|
*r | convertible to T const& | |
*r++ | convertible to T const& | { MAGIC tmp = *r; ++r; return tmp; } |
MAGIC is a problem because...
*r and *r++ may return:
- T
- T const&
- T&
- T&&
Because explaining magic is a whole other talk.
Find me after if interested.
T | proxy| T& | T const& | T&&
*r
*r++
Persistent values (vector)
Generators
Binds to T const&!
{
auto tmp = *r; // move or copy
++r;
return tmp; // move
} -> T
{
auto tmp = *r; // move or copy
++r;
return tmp; // move
} -> T
using T = std::unique_ptr<int>;
struct proxy {
operator T() const {
return make_unique<int>(0);
}
};
struct iterator {
proxy operator*() const {
return proxy{};
}
};
Yup, works.
#include <type_traits>
#include <memory>
using T = std::unique_ptr<int>;
struct proxy {
operator T() const { return std::make_unique<int>(0); }
};
struct iterator {
proxy operator*() const {
return proxy{};
}
};
int main() {
iterator x;
T const& y = *x;
static_assert(std::is_convertible<decltype(*x),
T const&>::value, "");
}
T& binds to T const&.
If you need that, you are asking for a mutable iterator, not an InputIterator, and have an extra requirement.
Operational semantics of *r++
{
T tmp = *r;
++r;
return tmp;
}
move
move
The move works because we are not converting.
how do we ask for T const& or move constructible?
T
Current wording
Operational semantics of *r++
{
MAGIC tmp = *r;
++r;
return tmp;
}
{
T tmp = *r;
++r;
return tmp;
}
T
MAGIC needs to be convertible to
T const&, and persist the object IF the iterator doesn't hang on to it.
MAGIC
Current wording
What we need
Operational semantics of *r++
{
MAGIC tmp = *r;
++r;
return tmp;
}
{
T tmp = *r;
++r;
return tmp;
}
MAGIC
T
MAGIC needs to be convertible to
T const&, persist the object if necessary, but we also need convertibility to T&&
Current wording
What we need
Operational semantics of *r++
{
MAGIC tmp = *r;
++r;
return tmp;
}
{
T tmp = *r;
++r;
return tmp;
}
Is T&&
T
This *always* moves
MAGIC needs to persist if necessary but convert to T&&, which converts to
T const&.
MAGIC
We only want to move IF ACTUALLY MOVING
We need help with MAGIC definition, but the current one is not good enough.
I also want holes poked into the T const& convertibility, but currently I don't see any.
There are none. All of them specify convertibility in addition already. (<numeric>, <algorithm> survey done)