We need a function that will be able to return both int32 and int64. How to implement it most competently?
The goal is to bring to the function a code that receives integers of a specified size from a binary file by the specified endian.
We need a function that will be able to return both int32 and int64. How to implement it most competently?
The goal is to bring to the function a code that receives integers of a specified size from a binary file by the specified endian.
Option 1. I offer you an option with a 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; } With reverse indian it is similar but ((char*)&ret)[sizeof(T)-i-1] Perhaps this variant is crooked, I don’t know how to write with castes.
When using, you have to specify the desired type getNumData<int32>(q,0) this will allow you to immediately decode all 3-4 options from 8bit to 64.
If the getNumData converted to such a template<typename T> void getNumData(T& ret, void* data, int offs) then you don’t have to specify <int32> - you can write getNumData(retvar,q,0); The option is quite good in speed.
Still there are options:
To return the union (simply, but it will be a) the loss of the sign b) is impossible for the reverse indian.
Return int64 and cast (impossible for reverse indian)
Return the class, and set the caste rules for each type (more code, convenient, but you can get confused) - implicit cast.
Option 2. You can get rid of the extra <> "sacrificing" an extra class (some compilers will eat the struct , but all the operators belong to the class classes). I will show implicit cast - that's what it's called, i.e. the compiler looks to which class the caste goes, and makes a call to a specific operator. It is necessary to check this method with a disassembler so that the compiler would not create new and delete calls. For one variable, the compiler does not create constructors destructors. There may be a loss of speed during use, so it’s best to check The simplified scheme is:
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); The disadvantage - instead of one call - there will be two calls (some compilers can make 4-re, but specifying inline can compile both one call and zero, depends on the compiler), but it is more convenient to use. The disadvantage is more code - for each type you will have to write a separate caste, unlike the first option, but sometimes this separation allows you to add speed (it will be easier to get rid of cycles and n p).
In C ++, you cannot overload functions by the return value. In other words, the next overload is wrong.
int32 getInt(); int64 getInt(); But there are other ways:
Make two different functions and call the necessary:
int32 getInt32(); int64 getInt64(); You can make this function template, but it doesn’t change much.
Do not return value at all. Pass an index or links to both:
void getInt(int32&, int64&); Return a structure from a pair of elements.
struct UniversalInt { int32 i32; int64 i64; }; UniversalInt getInt(); But there are problems: firstly, regardless of the resultant, the memory will be allocated for both elements, and one is used, and secondly, it is not known what type was returned.
Use union . This will partially solve the problem of allocating extra memory. This option should not be used in such an implementation at all.
union UniversalInt { int32 i32; int64 i64; }; UniversalInt getInt(); To union add information about the returned type. The good news is that this structure already exists - std::variant ; the bad news is that the added std::variant was only in C ++ 17.
std::variant<int32, int64> getInt(); Alternatively, you can use boost::variant . For POD types, this structure will look pretty simple and you can write it yourself. As soon as it turns out that a suitable variant makes sense to think about using a visitor pattern.
In my opinion the best option will be the first.
Source: https://ru.stackoverflow.com/questions/852578/
All Articles