I'm trying to define my own datatype (called sfloat) that's similar to a float, but uses a different number of mantissa bits and exponential bits to better suit my data range and precision. The goal is to define a new datatype that can replace the float in already existing applications. Everything's working out so far, except that I have been unable to override or define the unsigned operator such that
unsigned sfloat(3.141527)
would return the unsigned version of this class, usfloat(3.141527).
It seems like the unsigned specifier might be able to be overloaded since VS intellisense is not complaining in the header file:
sfloat::sfloat(float f) { m_data = get16bit(f); }
operator unsigned() { /*Do stuff here */ };
But it's not working in declaration and initialization:
unsigned sfloat myPi= 3.141527; // Error: expected a ';'
I don't even know if this is possible to do in C++, and I'm curious if anybody has done this before?
Due to C++ default-int for signedness, operator unsigned () is just a syntactic shorthand for operator unsigned int (). User-defined types cannot be declared signed or unsigned.
There is no direct way to accomplish what you're trying to do. As #Angew mentioned in his answer, unsigned cannot be applied to user-defined types.
On the other hand, you could fake this up by defining types named sfloat and unsigned_sfloat which had conversions defined between them. You could then write
unsigned_sfloat x(137.0f); // Close enough. ^_^
And then define a conversion operator as
operator unsigned_sfloat() {
... implementation here ...
}
This gives you something syntactically close to what you want and works around the fact that the language does not let you use the unsigned keyword to modify a custom type.
Hope this helps!
You could mock something like this up with templates:
#include <type_traits>
template <typename T = int>
class myfloat
{
static_assert(std::is_same<T, int>::value, "myfloat should only be instantiated on \"signed\" and \"unsigned\" ints");
const bool isSigned = true;
// the rest of the signed implementation
};
template <>
class myfloat<unsigned>
{
const bool isSigned = false;
// the rest of the unsigned implementation
};
int main()
{
myfloat<> a; // signed
myfloat<signed> b; // signed
myfloat<unsigned> c; // unsigned
// myfloat<float> d; // <-- compile error
return 0;
}
Try the following:
template<typename T>
struct Unsigned;
and use it like:
Unsigned<sfloat> usfloat
Now, you have to specialize Unsigned for your type Float, but this should communicate "is an unsigned version of Float" slightly better than an unsigned_sfloat type. I'd only bother with this if you where building an entire library of such types you might want to attach Unsigned<> to, however.
Related
I have such expressions in my code:
QByteArray idx0 = ...
unsigned short ushortIdx0;
if ( idx0.size() >= sizeof(ushortIdx0) ) {
// Do something
}
But I'm getting the warning:
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if ( idx0.size() >= sizeof(ushortIdx0) ) {
~~~~~~~~~~~~^~~~~~~~~~
Why size() of QByteArray is returned as int rather than unsigned int? How can I get rid of this warning safely?
Some folk feel that the introduction of unsigned types into C all those years ago was a bad idea. Such types found themselves introduced into C++, where they are deeply embedded in the C++ Standard Library and operator return types.
Yes, sizeof must, by the standard, return an unsigned type.
The Qt developers adopt the modern thinking that the unsigned types were a bad idea, and favour instead making the return type of size a signed type. Personally I find it idiosyncratic.
To solve, you could (i) live with the warning, (ii) switch it off for the duration of the function, or (iii) write something like
(std::size_t)idx0.size() >= sizeof(ushortIdx0)
at the expense of clarity.
Why size() of QByteArray is returned as int rather than unsigned int?
I literally have no idea why Qt chose a signed return for size(). However, there are good reasons to use a signed instead of an unsigned.
One infamous example where a unsigned size() fails miserably is this quite innocent looking loop:
for (int i = 0; i < some_container.size() - 1; ++i) {
do_somehting(some_container[i] , some_container[i+1] );
}
Its not too uncommon to make the loop body operate on two elements and in that case its seems to be a valid choice to iterate only till some_container.size() - 1.
However, if the container is empty some_container.size() - 1 will silently (unsigned overflow is well defined) turn into the biggest value for the unsigned type. Hence, instead of avoiding the out-of-bounds access it leads to the maximum out of bounds you can get.
Note that there are easy fixes for this problem, but if size() does return a signed value, then there is no issue that needs to be fixed in the first place.
Because in Qt containers (like: QByteArray, QVector, ...) there are functions which can return a negative number, like: indexOf, lastIndexOf, contains, ... and some can accept negative numbers, like: mid, ...; So to be class-compatible or even framework-compatibe, developers use a signed type (int).
You can use standard c++ casting:
if ( static_cast<size_t>(idx0.size()) >= sizeof(ushortIdx0) )
The reason why is a duplicate part of the question, but the solution to the type mismatch is a valid problem to solve. For the comparisons of the kind you're doing, it'd probably be useful to factor them out, as they have a certain reusable meaning:
template <typename T> bool fitsIn(const QByteArray &a) {
return static_cast<int>(sizeof(T)) <= a.size();
}
template <typename T> bool fitsIn(T, const QByteArray &a) {
return fitsIn<T>(a);
}
if (fitsIn(ushortIdx0, idx0)) ...
Hopefully you'll have just a few kinds of such comparisons, and it'd make most sense to DRY (do not repeat yourself) and instead of a copypasta of casts, use functions dedicated to the task - functions that also express the intent of the original comparison. It then becomes easy to centralize handling of any corner cases you might wish to handle, i.e. when sizeof(T) > INT_MAX.
Another approach would be to define a new type to wrap size_t and adapt it to the types you need to use it with:
class size_of {
size_t val;
template <typename T> static typename std::enable_if<std::is_signed<T>::value, size_t>::type fromSigned(T sVal) {
return (sVal > 0) ? static_cast<size_t>(sVal) : 0;
}
public:
template <typename T, typename U = std::enable_if<std::is_scalar<T>::value>::type>
size_of(const T&) : val(sizeof(T)) {}
size_of(const QByteArray &a) : val(fromSigned(a.size())) {}
...
bool operator>=(size_of o) const { return value >= o.value; }
};
if (size_of(idx0) >= size_of(ushortIdx0)) ...
This would conceptually extend sizeof and specialize it for comparison(s) and nothing else.
I'm working with a library that uses a C interface and several functions that pass a pointer to a struct as the output (not return).
The struct is something like
struct S {
short a;
short b;
union {
char cdata[5];
short sdata[5];
long ldata[5];
float fdata[5];
double dfdata[5];
} u;
}
I've written some template classes that can provide access to this in the form
auto parameter = MyClass<double>(constructor parameters);
parameter.SetValue(5.2); // Sets u.dfdata[0] = 5.2;
// other functions for changing index, or passing in a vector, etc
This is nice(ish) in that it abstracts away a lot of the required knowledge about structs, and only requires the user (still me, but whatever...) to know about the type of the parameter (double, float, long, short or char).
However, it's a compile time construct. The hardware I'm communicating with through this library is able to provide a function that has something like:
// renamed and tidied for ease of reading
// I don't have the source for this function, only docs
short GetParameter(short address, short* prevAddress, short* nextAddress,
S* parameter, Other* info);
where info can be parsed to tell me the type of the parameter. This would, if it were not compile time and different types, allow something like
std::vector<??> a;
a.push_back(MyClass<double>(args));
a.push_back(MyClass<short>(args));
where double and short can be read from the info struct as a short (0 = char, 1 = short...) and the other arguments can be read from the S struct.
I can build a std::vector<std::variant<MyClass<char>, MyClass<short>, ..., MyClass<double>>> but then trying to work out how to use a variant has left me confused if this is a good idea at all.
I want to be able to store sets of different types of parameters, for example for saving a complete configuration, but at the moment I think my functions are all compile-time calculations (variations on if constexpr(std::is_same_v<T, char>) { // do something with u.cdata[index] }).
If I want to be able to create lists with a single type, I can't (as far as I can work out) have virtual T ReadValue() or virtual void SetValue(T) because I can't use templating on virtual functions, and if I template the class (as I do now) then I have different (class) types which become hard to operate on.
An ideal solution would look something like
using valType = std::variant<char, short, long, float, double>;
using varType = std::variant<MyClass<char>, ..., MyClass<double>>;
// Read this from some file, or whatever
auto values = std::vector<valType> { 3, 2.6f, 17.2, 1523l };
std::vector<varType> paramList = MyFunctionThatReadsThroughParamToNextParam();
for (size_t i = 0; i < values.size(); i++) {
paramList[i].SetValue(values[i]);
// where the type contained in values[i] matches the type expected by paramList[i]
// ideally this would throw if the types were incorrect, but really
// any defined behaviour here would be great.
}
Is anything like this remotely possible?
#include <cstdint>
#include <iostream>
uint32_t ReadInt() { return 0; }
uint64_t ReadLong() { return 0; }
template<class SizeType>
class MyType
{
public:
SizeType Field;
MyType()
{
Field = sizeof(SizeType) == 8 ? ReadLong() : ReadInt();
}
};
int main()
{
MyType<uint32_t> m;
std::cout << m.Field;
}
I get a compiler warning because it looks like the the condition sizeof(MyType) == 4 is not being evaluated at compile time.
If it were we would have specialization and this wouldn't be a problem.
Anyway I could achieve this?
EDIT: What I really want to achieve is this:
Field = ReadLong();
OR
Field = ReadInt();
through template meta-programming. Can I do this without specializing the Read* functions? Given how powerful c++ templates I really feel like I'm missing some aha moment, because if I have to specialize Read* functions the rabbit hole continues to go deeper.
warning C4244: '=': conversion from 'int64_t' to 'uint32_t', possible loss of data for the int specialization
I get a compiler warning because it looks like the the condition sizeof(MyType) == 4 is not being evaluated at compile time.
No, it doesn't look like that at all. Whether the comparison is evaluated at compile time or not has no effect on the return type of the conditional expression.
If we simplify the example by removing the conditional and expand the template using the type that you used, we get this minimal reproduction:
uint32_t Field;
int64_t temp = ReadInt(); // temporary variable for exposition
Field = temp;
Clearly, the int64_t may contain a value that is much greater than can be represented by int32_t. If it does, then the correct value will be lost in conversion. The compiler warns about this possibility.
Why is the type of the conditional int64_t specifically you might ask. Well, the types of each subexpression is int64_t and uint32_t respectively, so the type must be one of those. The type of Field or the result of the comparison - even if evaluated at compile time - has no effect on which type is chosen. Instead, integral promotion rules are used in this case.
Anyway I could achieve this?
A template function should work:
template<class T>
T Read() {
static_assert(false, "not implemented");
}
template<>
uint64_t Read<uint64_t>() {
return ReadLong();
}
template<>
uint32_t Read<uint32_t>() {
return ReadInt();
}
// ...
Field = Read<SizeType>();
I get a compiler warning because it looks like the the condition sizeof(MyType) == 4 is not being evaluated at compile time
Wrong, it is evaluated at compile-time, but the conditional operator still has the bigger result-type of the arguments.
To fix it, just add a cast:
Field = sizeof(SizeType) == 8 ? (SizeType)ReadLong() : ReadInt();
Another approach using overload-resolution:
long ReadData(long) { return ReadLong(); }
int ReadData(int) { return ReadInt(); }
Field = ReadData(SizeType());
A conditional operator ?: expression evaluates to a single type, which accommodates both possible internal-to-the-construct result types.
This happens even when it's evaluated at compile time.
The common type in your case is the largest of the two possible integer types.
I'm getting a string containing raw binary data which needs to be converted to integers. The Problem is these values are not always in the same order and do not always appear. So the format of the binary data gets described in a config file and the type of the values read from the binary data is not known at compile time.
I'm thinking of a solution similar to this:
enum BinaryType {
TYPE_UINT16,
TYPE_UNIT32,
TYPE_INT32
};
long convert(BinaryType t, std::stringstream ss) {
long return_value;
switch(t) {
case TYPE_UINT16:
unsigned short us_value;
ss.read(&us_value, sizeof(unsigned short));
return_value = short;
break;
case TYPE_UINT32:
unsigned int ui_value;
ss.read(&ui_value, sizeof(unsigned int));
return_value = ui_value;
break;
case TYPE_INT32:
signed int si_value;
ss.read(&si_value, sizeof(signed int));
return_value = si_value;
break;
}
return return_value;
}
The goal is to output these values in decimal.
My Questions are:
This code is very repetitive. Is there a simpler solution? (Templates?)
should I make use of the standard types like signed int if the value needs to be 32 bit? What to use instead? Endianness?
A simple solution: define a base class for converters:
class Converter {
public:
virtual int_64 convert(std::stringstream& ss) = 0;
}
Next define a concrete converter for each binary type. Have a map/array mapping from binary types identifiers to your converters, e.g.:
Converter* converters[MAX_BINARY_TYPES];
converters[TYPE_UINT16] = new ConverterUINT16;
...
Now, you can use it like this (variables defined like in your function convert):
cout << converters[t]->convert(ss)
For portability, instead of basic types like int, long, etc, you should use int32_t, int64_t which are guaranteed to be the same on all systems.
Of course, if your code is meant to deal with different endianness, you need to deal with it explicitly. For the above example code you can have two different converters' sets, one for little endian data decoding, another for big endian. Another thing you can do is to write a wrapper class for std::stringstream, let's call it StringStream, which defines functions for reading int32, uint32, etc., and swaps the bytes if the endianness is different than the architecture of the system your code is running on. You can make the class a template and instantiate it with one of the two:
class SameByteOrder {
public:
template<typename T> static void swap(T &) {}
};
class OtherByteOrder {
public:
template<typename T> static void swap(T &o)
{
char *p = reinterpret_cast<char *>(&o);
size_t size = sizeof(T);
for (size_t i=0; i < size / 2; ++i)
std::swap(p[i], p[size - i - 1]);
}
};
then use the swap function inside your StringStream's functions to swap (or not) the bytes.
there are probably several ways I will expose my ignorance with this question :)
First, I think this is C++ code, but the extension of the file is .C (so maybe it is C?)
Anyway, I am trying to compile a program called Sundance (Sentence UNDerstanding ANd Concept Extraction) which is a Natural Language Processing tool. The compile error I get relates to the following:
// This class is used internally to keep track of constituents that are
// potential subjects for clauses during clause handling.
class PotentialXP {
public:
Constituent* XPPtr;
unsigned int Distance;
unsigned int ClauseIndex;
unsigned int ConstIndex;
PotentialXP() {
XPPtr = 0;
Distance = 0;
ClauseIndex = 0;
ConstIndex = 0;
};
operator int() const {
return (int)XPPtr;
};
void Set(Constituent* w,
unsigned int x,
unsigned int y,
unsigned int z){
XPPtr = w;
Distance = x;
ClauseIndex = y;
ConstIndex = z;
};
};
The error is "cast from ‘Constituent* const*’ to ‘int’ loses precision"
and relates to the lines:
operator int() const {
return (int)XPPtr;
};
I understand why I get an error. XPPtr is of type Constituent*, so how can it be converted to an integer? Can anyone figure out what the author of the code wants to do here, and how I might rewrite this line so it compliles? What is an operator function (if that's what you call it) for?
Any advice much appreciated!
That compiles fine for me. You are on a 64-bit machine, where size_t is larger than int.
Explanation: you can historically convert a pointer an int
struct Foo {};
int main ()
{
Foo * f = new Foo ();
std :: cout << (int)f; // Prints 43252435 or whatever
}
If you want an integer which is the same size as a pointer, use size_t or ssize_t.
And why on earth are you writing operator int() like that anyway? Do you want operator bool() to test for validity? In which case a function body of return NULL != XPPtr would be better style -- clearer, at least.
The line operator int() const states a how your object can be cast to int.
The Constituent* can be cast to int because both types are usually the same size. I do not think that this is what the programmer intended, since the raw pointer value is of no semantic use. Maybe there should be a field lookup? E.g:
operator int() const {
return (int)XPPtr->somevalue;
};