0

I have a vector<int> and functions that only accepts a vector<unsigned int> references.I know that I could change/template the functions(and this is likely the best thing to do), but ideally I would have a way to cast/convert the vector<unsigned int> reference to a vector<int> reference. I know that all values in the vector are positive, and non of the functions will even come close to overflowing the intigers.

I have tried using static_cast<vector<int>> but that doesnt work.

Edit: I say cast/convert of the references but I am not looking to create a new copy and reference that.

r123
  • 3
  • 2
  • 3
    Casting pointers to unrelated types is undefined behavior (type punning). You should not do it. – Marek R Apr 13 '23 at 11:27
  • 2
    There are two ways to solve this: Create a copy of the original vector, with the correct type; Or use a `std::vector` to begin with, no copying or conversion needed. – Some programmer dude Apr 13 '23 at 11:29
  • *I know that I could change/template the functions(and this is likely the best thing to do)* **Yes**, do that. The other way will end in tears. – Eljay Apr 13 '23 at 11:43
  • 1
    IMO, a function that only accepts a `vector` is bad by design. At least, the function should be a function template, where the vector value type is a template parameter. Even a better approach would be to use iterators as input parameters, or something as `std::span`. – Daniel Langr Apr 13 '23 at 11:57
  • @Daniel Langr, The values are 28 bit-bitflags. The actual hardcoded vector holds a uint32_t. I get the vector& from a libary. I think that it was a weird design choise to use a signed type for the bitflags. (It does this because when ran in debug mode, negative values are used for errors indication. This isnt a great reason in my opinion, but its what I will have to deal with.) – r123 Apr 13 '23 at 12:53
  • @r123 In that case, the "hardcoded vector" anyway needs to allocate its own memory and hold its own data. So why avoid conversion and prefer undefined behavior? This is why I wrote that that function was bad by design, if it accepts only `vector`. There is no gain when the hardcoded vector needs to allocate and copy data anyway. – Daniel Langr Apr 13 '23 at 12:59
  • @Daniel Langr Maybey hardcoded was the wrong word, haha. The functions take an unsigned vector reference and changes them. I could copy the signed vector reference into a signed vector and then after having the functions do their thing, and copy the unsigned vector back into the signed vector reference. The functions(and libary) on average acces way less then 1% of the vector. Thus this is a bit expensive, and I wanted a way to test the speed without these copies, for a proof of concept. – r123 Apr 13 '23 at 13:26

4 Answers4

3

you cannot cast, but you mention conversion is an option, which is easily done like this:

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

void main()
{
    std::vector<int> vec;
    foo({ vec.begin(), vec.end() });
}
Aedoro
  • 609
  • 1
  • 6
  • 21
1

Use std::transform to make a new copy of the vector with converted values. You cannot and should not reinterpret_cast to cast between unrelated types (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;
}
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19
0

One C++20,23 approach would be to use ranges:

#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

Ranges library has got a lot explore.

Red.Wave
  • 2,790
  • 11
  • 17
-1

There is no cast that does not result in undefined behaviour, but if you really want to do this then this will probably work in practise

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

Create a pointer, cast the pointer, then dereference. I used to do this sort of thing all the time when I was a C programmer.

Really though, you should not do this.

john
  • 85,011
  • 4
  • 57
  • 81
  • 1
    This should not be an acceptable answer. It is a programming habit that will set you up to fail at some point. – Pepijn Kramer Apr 13 '23 at 11:45
  • Ty, the program is only a quick proof-off-concept and not fital at all, so I will accept undefined behaviour for now. I had already tried something similar but using reinterpret_cast with references(also works) but I had forgotten to have that function return a reference(facepalm). – r123 Apr 13 '23 at 11:46
  • @PepijnKramer Kramer. I think that this answer is clear on this being undefined and dangerous behaviour. – r123 Apr 13 '23 at 11:49
  • Sure it is clear that it is dangerous, doubly so because "C" is not "C++". – Pepijn Kramer Apr 13 '23 at 14:32