<ranges>
: ranges::to
use range-based for loops in append branches · Issue #5172 · microsoft/STL (original) (raw)
for (auto&& _Elem : _Range) { |
---|
using _ElemTy = decltype(_Elem); |
if constexpr (_Can_emplace_back<_Container, _ElemTy>) { |
_Cont.emplace_back(_STD forward<_ElemTy>(_Elem)); |
} else if constexpr (_Can_push_back<_Container, _ElemTy>) { |
_Cont.push_back(_STD forward<_ElemTy>(_Elem)); |
} else if constexpr (_Can_emplace_end<_Container, _ElemTy>) { |
_Cont.emplace(_Cont.end(), _STD forward<_ElemTy>(_Elem)); |
} else { |
_STL_INTERNAL_STATIC_ASSERT(_Can_insert_end<_Container, _ElemTy>); |
_Cont.insert(_Cont.end(), _STD forward<_ElemTy>(_Elem)); |
} |
} |
To save the include overhead of ranges::for_each
, MSVC-STL uses range-based for loop to iterate over the range. However, this is not guaranteed to be well-formed as the former does not extract iterators and sentinels through ranges::begin
/ranges::end
.
A disgusting and contrived case could be:
https://godbolt.org/z/Kc3dsvnfW
#include
struct Vector { void push_back(int); };
struct OnlyADLRange { void begin() = delete; void end() = delete; friend int* begin(OnlyADLRange&); friend int* end(OnlyADLRange&); };
int main() { std::ranges::contiguous_range auto r = OnlyADLRange{}; auto v = r | std::ranges::to(); // only well-formed in libstdc++ }
Above, only libstdc++ explicitly uses ranges::begin
/ranges::end
to get iterators-pair and iterates over the ranges via a while loop so there is no issue.