Преобразование vector<int> в vector<unsigned int>

У меня есть vector<int> и функции, которые принимают только ссылки vector<unsigned int>. Я знаю, что могу изменить / создать шаблон функций (и это, вероятно, лучше всего сделать), но в идеале у меня был бы способ преобразовать / преобразовать ссылку vector<unsigned int> в ссылка vector<int>. Я знаю, что все значения в векторе положительны, и ни одна из функций даже не приблизится к переполнению целых чисел.

Я пытался использовать static_cast<vector<int>>, но это не работает.

Редактировать: Я говорю приведение/преобразование ссылок, но я не собираюсь создавать новую копию и ссылаться на нее.

Приведение указателей к несвязанным типам является неопределенным поведением (каламбур). Вы не должны этого делать.

Marek R 13.04.2023 13:27

Есть два способа решить эту проблему: создать копию исходного вектора с правильным типом; Или используйте std::vector<unsigned int> для начала, без копирования или преобразования.

Some programmer dude 13.04.2023 13:29

Я знаю, что я мог бы изменить/образовать функции (и это, вероятно, лучший способ сделать). Да, сделайте это. Другой путь закончится слезами.

Eljay 13.04.2023 13:43

ИМО, функция, которая принимает только vector<unsigned int>, плоха по замыслу. По крайней мере, функция должна быть шаблоном функции, где тип значения вектора является параметром шаблона. Еще лучшим подходом было бы использование итераторов в качестве входных параметров или что-то вроде std::span.

Daniel Langr 13.04.2023 13:57

@Daniel Langr, значения представляют собой 28-битные флаги. Фактический жестко закодированный вектор содержит uint32_t. Я получаю вектор <int32_t>& из библиотеки. Я думаю, что использование знакового типа для битовых флагов было странным решением. (Это происходит потому, что при запуске в режиме отладки для индикации ошибок используются отрицательные значения. На мой взгляд, это не очень хорошая причина, но с этим мне придется иметь дело.)

r123 13.04.2023 14:53

@ r123 В этом случае «жестко закодированный вектор» в любом случае должен выделять собственную память и хранить свои данные. Так зачем избегать преобразования и предпочитать неопределенное поведение? Вот почему я написал, что эта функция плохая по дизайну, если она принимает только vector<unsigned int>. Нет никакой выгоды, когда жестко заданный вектор все равно должен выделять и копировать данные.

Daniel Langr 13.04.2023 14:59

@Daniel Langr Может быть, «жестко закодированный» было неправильным словом, ха-ха. Функции берут беззнаковые векторные ссылки и изменяют их. Я мог бы скопировать ссылку на вектор со знаком в вектор со знаком, а затем, после того как функции сделают свое дело, скопировать вектор без знака обратно в ссылку на вектор со знаком. Функции (и библиотеки) в среднем получают доступ менее чем к 1% вектора. Таким образом, это немного дорого, и я хотел проверить скорость без этих копий для проверки концепции.

r123 13.04.2023 15:26
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
180
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

вы не можете разыгрывать, но вы упоминаете, что преобразование - это вариант, который легко сделать следующим образом:

void foo(const std::vector<unsigned int>& data)
{
     // ...
}

void main()
{
    std::vector<int> vec;
    foo({ vec.begin(), vec.end() });
}

Работает для int/unsigned int, потому что есть неявное преобразование.

Pepijn Kramer 13.04.2023 13:40

Благодарю за ваш ответ. Я сказал приведение/преобразование ссылок, но я не собираюсь создавать новую копию и ссылаться на нее.

r123 13.04.2023 13:53
Ответ принят как подходящий

Нет приведения, которое не приводит к неопределенному поведению, но если вы действительно хотите это сделать, то это, вероятно, сработает на практике.

*reinterpret_cast<vector<unsigned int>*>(&vec)

Создайте указатель, приведите указатель, затем разыменуйте. Я делал подобные вещи все время, когда был программистом на C.

Хотя на самом деле этого делать не следует.

Это не должно быть приемлемым ответом. Это привычка программирования, которая в какой-то момент приведет вас к неудаче.

Pepijn Kramer 13.04.2023 13:45

Тай, программа представляет собой всего лишь быстро проверочный концепт и совсем не годится, так что пока я приму неопределенное поведение. Я уже пробовал что-то подобное, но использовал reinterpret_cast со ссылками (тоже работает), но я забыл, чтобы эта функция возвращала ссылку (facepalm).

r123 13.04.2023 13:46

@PepijnKramer Крамер. Я думаю, что этот ответ ясен в том, что это неопределенное и опасное поведение.

r123 13.04.2023 13:49

Конечно, ясно, что это опасно, вдвойне потому, что "C" - это не "C++".

Pepijn Kramer 13.04.2023 16:32

Используйте 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

В библиотеке диапазонов есть много возможностей для изучения.

Другие вопросы по теме