У меня есть большая кодовая база, которая содержит код, связанный с матрицей, используя uint_fast64_t в качестве типа индекса. Чтобы использовать GMM в качестве решающего бэкэнда мне нужно преобразовать (привести!) векторы из:
std::vector<uint_fast64_t, std::allocator<uint_fast64_t>>
в GMMs внутренний формат
std::vector<unsigned long long, std::allocator<unsigned long long>>
В MSVC2012 для uint_fast64_t используется typedef’d для unsigned long long, поэтому оба выражения «одинаковы».
Мне хорошо известно, что на самом деле они НЕ одного и того же типа, так как unsigned long long может иметь длину точно 64 бита (long) (как это определено реализацией), а длина uint_fast64_t составляет не менее 64 бит. (—но-ненавистники;))
К сожалению, GCC4.7 и Clang 3.4 называют uint_fast64_t внутренним типом, что делает невозможным любой тип приведения.
Кроме того, кажется, что в какой-то момент clang интерпретирует uint_fast64_t как unsigned long, что делает его еще более несовместимым с длинным беззнаковым определением.
Какие пути вы видите из моих страданий?
Является ли мой единственный вариант замены беззнакового long long в GMM-коде вручную?
Следующее является не очень переносимым, но работающим решением:
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);
Вы должны скомпилировать это с выключенным псевдонимом строгого типа (например, Clang’s -fno-strict-aliasing
).
Он основан на поведении, которое не определено в стандарте, но, передав соответствующий флаг (ы) компилятора, вы можете фактически заставить свой компилятор обеспечить непротиворечивое определение.
static_cast
следует делать свое дело, так как все они числовые типы (при условии, что ваши fast64 int не используют более 64 бит).
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);