Конструктор строки MSVS, который принимает пару итераторов, выглядит как
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>());
}
и _Construct
возможные звонки
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
}
Важным битом является push_back(static_cast<_Elem>(*_First));
. Обычно вы не сможете назначить std::byte
напрямую другому типу, поскольку это перечисление с ограничением, но, поскольку есть static_cast
, вы можете обойти это.
Вот почему вы можете использовать диапазон байтов для инициализации std::string
.
При этом конструктор итератора требует от [sequence.reqmts] - Таблица 68 , что
T
должен быть EmplaceConstructible в X
с *i
.
и [container.requirements.general] /15.5 утверждает, что EmplaceConstructible
означает
T
является EmplaceConstructible в X
из args
, для нуля или более аргументов args
, означает, что следующее выражение правильно сформировано:
allocator_traits<A>::construct(m, p, args)
и construct
определены в [allocator.requirements] - Таблица 33 как
Эффекты: Создает объект типа C в c
По умолчанию ::new ((void*)c)C(forward<Args>(args)...)
Так что до сих пор неясно, разрешено это или нет.