У меня есть vector<int> и функции, которые принимают только ссылки vector<unsigned int>. Я знаю, что могу изменить / создать шаблон функций (и это, вероятно, лучше всего сделать), но в идеале у меня был бы способ преобразовать / преобразовать ссылку vector<unsigned int> в ссылка vector<int>. Я знаю, что все значения в векторе положительны, и ни одна из функций даже не приблизится к переполнению целых чисел.
Я пытался использовать static_cast<vector<int>>, но это не работает.
Редактировать: Я говорю приведение/преобразование ссылок, но я не собираюсь создавать новую копию и ссылаться на нее.
Есть два способа решить эту проблему: создать копию исходного вектора с правильным типом; Или используйте std::vector<unsigned int> для начала, без копирования или преобразования.
Я знаю, что я мог бы изменить/образовать функции (и это, вероятно, лучший способ сделать). Да, сделайте это. Другой путь закончится слезами.
ИМО, функция, которая принимает только vector<unsigned int>, плоха по замыслу. По крайней мере, функция должна быть шаблоном функции, где тип значения вектора является параметром шаблона. Еще лучшим подходом было бы использование итераторов в качестве входных параметров или что-то вроде std::span.
@Daniel Langr, значения представляют собой 28-битные флаги. Фактический жестко закодированный вектор содержит uint32_t. Я получаю вектор <int32_t>& из библиотеки. Я думаю, что использование знакового типа для битовых флагов было странным решением. (Это происходит потому, что при запуске в режиме отладки для индикации ошибок используются отрицательные значения. На мой взгляд, это не очень хорошая причина, но с этим мне придется иметь дело.)
@ r123 В этом случае «жестко закодированный вектор» в любом случае должен выделять собственную память и хранить свои данные. Так зачем избегать преобразования и предпочитать неопределенное поведение? Вот почему я написал, что эта функция плохая по дизайну, если она принимает только vector<unsigned int>. Нет никакой выгоды, когда жестко заданный вектор все равно должен выделять и копировать данные.
@Daniel Langr Может быть, «жестко закодированный» было неправильным словом, ха-ха. Функции берут беззнаковые векторные ссылки и изменяют их. Я мог бы скопировать ссылку на вектор со знаком в вектор со знаком, а затем, после того как функции сделают свое дело, скопировать вектор без знака обратно в ссылку на вектор со знаком. Функции (и библиотеки) в среднем получают доступ менее чем к 1% вектора. Таким образом, это немного дорого, и я хотел проверить скорость без этих копий для проверки концепции.





вы не можете разыгрывать, но вы упоминаете, что преобразование - это вариант, который легко сделать следующим образом:
void foo(const std::vector<unsigned int>& data)
{
// ...
}
void main()
{
std::vector<int> vec;
foo({ vec.begin(), vec.end() });
}
Работает для int/unsigned int, потому что есть неявное преобразование.
Благодарю за ваш ответ. Я сказал приведение/преобразование ссылок, но я не собираюсь создавать новую копию и ссылаться на нее.
Нет приведения, которое не приводит к неопределенному поведению, но если вы действительно хотите это сделать, то это, вероятно, сработает на практике.
*reinterpret_cast<vector<unsigned int>*>(&vec)
Создайте указатель, приведите указатель, затем разыменуйте. Я делал подобные вещи все время, когда был программистом на C.
Хотя на самом деле этого делать не следует.
Это не должно быть приемлемым ответом. Это привычка программирования, которая в какой-то момент приведет вас к неудаче.
Тай, программа представляет собой всего лишь быстро проверочный концепт и совсем не годится, так что пока я приму неопределенное поведение. Я уже пробовал что-то подобное, но использовал reinterpret_cast со ссылками (тоже работает), но я забыл, чтобы эта функция возвращала ссылку (facepalm).
@PepijnKramer Крамер. Я думаю, что этот ответ ясен в том, что это неопределенное и опасное поведение.
Конечно, ясно, что это опасно, вдвойне потому, что "C" - это не "C++".
Используйте std::transform, чтобы создать новую копию вектора с преобразованными значениями. Вы не можете и не должны переинтерпретировать_приведение для приведения между несвязанными типами (std::vector<int> != std::vector<unsigned int>)
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
int main()
{
std::vector<int> values{ 1,2,3,4,5 };
std::vector<unsigned int> converted_values;
// avoid raw for loops
std::transform(values.begin(), values.end(), std::back_inserter(converted_values), [](const int value)
{
return static_cast<unsigned int>(value);
});
for (const auto& value : convered_values)
{
std::cout << value << " ";
}
return 0;
}
Один из подходов С++ 20,23 заключается в использовании диапазонов:
#incluce <ranges>
template<typename result>
constexpr auto cast_trans = std::views::transform( // C++20
[](auto const& x)
{ return static_cast<result>(x); });
std::vector<int> vint;
auto ruint = vint | cast_trans<unsigned>;
auto vuint = ruint | std::ranges::to<std::vector>; // C++23
В библиотеке диапазонов есть много возможностей для изучения.
Приведение указателей к несвязанным типам является неопределенным поведением (каламбур). Вы не должны этого делать.