Нужна функция, которая будет способна возвращать как int32, так и int64. Как это наиболее грамотно реализовать?
Цель в том, чтобы вынести в функцию код, получающий из бинарного файла целые числа указанного размера по указанному эндиану.
Вариант 1. Предлагаю вам вариант с template
template<typename T> T getNumData(void* buff, int offs){
T ret;
for (int i=0;i<sizeof(T);i++) ((char*)&ret)[i] = ((char*)buff)[i+offs];
return ret;
}
С обратным индианом аналогично но ((char*)&ret)[sizeof(T)-i-1]
Возможно этот вариант кривеникий, как правильно с кастами писать - не знаю.
При использовании придётся указывать желаемый тип getNumData<int32>(q,0)
это вам позволит сразу декодировать все 3-4 варианта от 8бит до 64.
Если ф-цию getNumData
переделать на такую template<typename T> void getNumData(T& ret, void* data, int offs)
тогда не придётся указывать <int32>
- можно будет записать getNumData(retvar,q,0);
Вариант достаточно хороший по быстродействию.
Еще есть варианты:
Вернуть union (просто, но будет а) потеря знака б) невозможно для обратного indian.
Вернуть int64 и кастить (невозможно для обратного indian)
Вернуть класс, и прописать правила каста к каждому из типов (больше кода, удобно, но можно запутаться) - implicit cast.
Вариант 2. От лишних <>
можно избавится "жертвуя" дополнительным классом (некоторые компиляторы съедят struct
, но всётаки операторы относятся к классам class
). Покажу implicit cast - так это называется, т.е. компилятор смотрит к какому классу идёт каст, и делает вызов определенного оператора. Нужно этот метод проверять дизассемблером, что б компилятор вызовы new и delete не лепил. Для одной переменной компилятор не создаёт конструкторы деструкторы. При использовании могут быть потери скорости, поэтому лучше проверить. В упрощённой схеме получится так:
class /*struct*/ autocast {
public:
void *data;
// кастим к int32, в комментарии вариант для обратного indian
operator int32() { return *(int32*)data; /*return getData<int>(data,0)*/ }
// кастим к int64
operator int64() { return *(int64*)data; }
};
//И можно запилить
autocast /*inline*/ getNumDataVar(void* data){ /*Дописать offs*/
autocast ret;
ret.data = data;
return ret;
}
// вызов делается так (но тип слева должен быть одним из тех,
// для которого существует оператор implicit cast)
int32 query = getNumDataVar(q);
Недостаток - вместо одного вызова - будет два вызова (некоторые компиляторы могут сделать 4-ре, но указанием inline
может быть скомпилирован как один вызов так и ноль, зависит от компилятора), зато удобнее в использовании. Недостаток - больше кода - для каждого типа прийдётся писать отдельный каст, в отличии от первого варианта, но иногда такое разделение позволяет добавить быстродействие (легче избавится от циклов и т п).
В C++ нельзя перегружать функции по возвращаемому значению. Иными словами следующая перегрузка неправльна
int32 getInt();
int64 getInt();
Но есть другие способы:
Сделать две разные функции и вызывать необходимую:
int32 getInt32();
int64 getInt64();
Можно сделать эту функцию шаблонной но это особо ничего не изменит.
Не возвращать значение вообще. Передавать указатель или ссылки на обеъкты:
void getInt(int32&, int64&);
Возвращать структуру из пары элементов
struct UniversalInt {
int32 i32;
int64 i64;
};
UniversalInt getInt();
Но тут вознкают проблемы: во-первых не зависимо от резульата память будет выделена под оба элемента, а использован один, а во-вторых неизвестно какой тип именно был возвращен.
Использовать union
. Это частично решит проблему с выделением лишней памяти. Этот вариант не стоит использовать в такой реализации вообще.
union UniversalInt {
int32 i32;
int64 i64;
};
UniversalInt getInt();
К union
добавить информацию о возвращенном типе. Хорошая новость заключатся в том, что такая структура уже есть - std::variant
; плохая новость заключается в том, что добавлен std::variant
был только в С++17.
std::variant<int32, int64> getInt();
Как вариант можно использовать boost::variant
.
Для POD типов подобная структура будет довольно просто выглядеть и её можно написать самостоятельно.
Как только оказывается, что подходит variant
имеет смысл задуматься об использовании шаблона посетитель.
На мой взгляд лучшим вариантом будет первый.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Как поворачивать Perspective Camera, когда по экрану проводят пальцем (как в Майнкрафте Bedrock Edition)?
Код взят для примера с офф сайта ваадина: