MSVS's string constructor that takes an iterator pair looks like
template<class _Iter,
class = enable_if_t<_Is_iterator_v<_Iter>>>
basic_string(_Iter _First, _Iter _Last, const _Alloc& _Al = _Alloc())
: _Mybase(_Al)
{ // construct from [_First, _Last) with optional allocator
_Tidy_init();
_Adl_verify_range(_First, _Last);
_Construct(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Iter_cat_t<_Iter>());
}
And _Construct
eventualy calls
template<class _Iter>
void _Construct(_Iter _First, const _Iter _Last, input_iterator_tag)
{ // initialize from [_First, _Last), input iterators
_TRY_BEGIN
for (; _First != _Last; ++_First)
{
push_back(static_cast<_Elem>(*_First));
}
_CATCH_ALL
_Tidy_deallocate();
_RERAISE;
_CATCH_END
}
With the important bit being push_back(static_cast<_Elem>(*_First));
. Normally you would not be able to assign a std::byte
directly to another type since it is a scoped enumeration but since there is a static_cast
you get around that.
This is why you are able to use a range of bytes to initialize a std::string
.
That said the iterator constructor requires from [sequence.reqmts] - Table 68 that
T
shall be EmplaceConstructible into X
from *i
.
and [container.requirements.general]/15.5 states that EmplaceConstructible
means
T
is EmplaceConstructible into X
from args
, for zero or more arguments args
, means that the following expression is well-formed:
allocator_traits<A>::construct(m, p, args)
and construct
is defined in [allocator.requirements] - Table 33 as
Effects: Constructs an object of type C at c
Default ::new ((void*)c)C(forward<Args>(args)...)
So it is still unclear if this is allowed or not.
std::byte
is distinct from the other types you mention in that it's isn't considered a character type and is not considered an integral type. – François Andrieuxstd::byte
. – NathanOliver