Can I achieve type equivalency between uint_fast64_t and unsigned long long?

577 views Asked by At

I have a large codebase that contains matrix-related code using uint_fast64_t as an index type. To make use of GMM as a solver backend, I need to convert (cast!) vectors from:

std::vector<uint_fast64_t, std::allocator<uint_fast64_t>>

to GMMs internal format

std::vector<unsigned long long, std::allocator<unsigned long long>>

Under MSVC2012, uint_fast64_t is typedef'd to unsigned long long, so both expressions are "the same".

I am well aware that they are, in fact, NOT the same type, as unsigned long long may be exactly 64bits long (long) (as it is implementation defined) and uint_fast64_t is at least 64bits long. ( --no-haters ;) )

Sadly, GCC4.7 and Clang 3.4 known uint_fast64_t as an internal type, making any type of cast impossible.

Additionally it seems that at some point, clang interprets uint_fast64_t as unsigned long - making it even more incompatible to the unsigned long long definition.

Which ways do you see out of my misery?

Is my only option replacing the unsigned long long in GMMs Code by hand?

2

There are 2 answers

2
Angew is no longer proud of SO On BEST ANSWER

The following is a not-really-portable, but working solution:

static_assert(sizeof(uint_fast64_t) == sizeof(unsigned long long), "This code relies on equivalence of uint_fast64_t and unsigned long long");

std::vector<uint_fast64_t, std::allocator<uint_fast64_t>> src;

std::vector<unsigned long long, std::allocator<unsigned long long>> &after_cast = 
  *reinterpret_cast<std::vector<unsigned long long, std::allocator<unsigned long long>> *>(&src);

You have to compile this with strict type aliasing turned off (such as Clang's -fno-strict-aliasing).

It relies on behaviour which is undefined in the standard, but by passing the appropriate compiler flag(s), you can actually make your compiler provide a consistent definition.

5
Zac Howland On

static_cast should do the trick since they are all numeric types (providing that your fast64 ints are not using more than 64-bits).

unsigned long long convert_to_ull(uint_fast64_t i)
{
    return static_cast<unsigned long long>(i);
}


std::vector<uint_fast64_t> origData;
// fill in origData
std::vector<unsigned long long> data;
data.reserve(origData.size());
std::transform(origData.begin(), origData.end(), data.begin(), convert_to_ull);