Я попытался решить проблему, как описано в комментариях. Для простоты я использовал только необработанные указатели:
template <typename T, typename... Vs, size_t... Is>
void allocate_helper(T* ptr, std::tuple<Vs...> v, std::index_sequence<Is...>)
{
new (ptr) T(std::forward<Vs>(std::get<Is>(v))...);
}
template <typename T, typename V>
void allocate_array_helper(T* ptr, V v)
{
allocate_helper<T>(ptr, std::move(v),
std::make_index_sequence<std::tuple_size_v<V>>{});
}
template <typename T, typename V, typename... Vs>
void allocate_array_helper(T* ptr, V v, Vs... vs)
{
allocate_helper<T>(ptr, std::move(v),
std::make_index_sequence<std::tuple_size_v<V>>{});
try
{
allocate_array_helper<T>(++ptr, std::move(vs)...);
}
catch (...)
{
std::destroy_at(ptr);
throw;
}
}
template <typename T, typename... Vs>
T* allocate_array(Vs... vs)
{
T* ptr = (T*)::operator new(sizeof(T) * sizeof...(Vs));
try
{
allocate_array_helper<T>(ptr, std::move(vs)...);
}
catch (...)
{
::operator delete(ptr);
throw;
}
return ptr;
}
Это работает для меня в этом примере, так что он печатает hello world!
, move-from s1
и сохраняет s2
:
int main()
{
std::string s1("world");
std::string s2("!");
std::string* ptr = allocate_array<std::string>(
std::forward_as_tuple("hello"),
std::forward_as_tuple(3, ' '),
std::forward_as_tuple(s1.begin(), s1.end()),
std::forward_as_tuple(std::move(s2))
);
for (size_t i = 0; i < 4; i++)
std::cout << ptr[i];
std::destroy(ptr, ptr + 4);
::operator delete(ptr);
}
Но, честно говоря, я не совсем уверен, что мое решение на 100% правильное.
Демонстрационная версия здесь .
РЕДАКТИРОВАТЬ: Я добавил обработку исключений, что очень важно здесь.