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;
};
Related
Things seem to become complicated when dealing with compound C++ types.
For example, how to analyze the type of token fp in the codes below?
int *f(int *p, int a)
{
return p + a;
}
int *(*fp())(int *, int)
{
return f;
};
Is there a explanation on syntax for the codes?
You start on the name, then proceed outwards, handling stuff on the right first, then stuff on the left, except when parentheses change that:
fp // `fp` is
fp() // (look to the right) a function without parameters, returning
*fp() // (look to the left) a pointer to
(*fp()) // (skip parentheses)
(*fp())(int *, int) // (look to the right) a function taking `(int *, int)`, returning
*(*fp())(int *, int) // (look to the left) a pointer to
int *(*fp())(int *, int) // int
Personally I think best way is to not use such complex declaration and use typedef or using (type alias) to make clear what is an intention:
int *f(int *p, int a)
{
return p + a;
}
using ProgressPointerFunPtr = int* (*)(int *p, int a);
// or pre C++11 style:
// typedef int* (*ProgressPointerFunPtr)(int *p, int a);
ProgressPointerFunPtr fp()
{
return f;
}
This way it is easier to read and it is more clear what code is doing.
Bonus gain is that when you decide to do changes in function pointer it is much easier to do in already existing code, since hunting for places when this change is needed is quicker or not needed at all.
What does this error message mean?
error: call of overloaded ‘setval(int)’ is ambiguous
huge.cpp:18: note: candidates are: void huge::setval(unsigned int)
huge.cpp:28: note: void huge::setval(const char*)
My code looks like this:
#include <iostream>
#define BYTES 8
using namespace std ;
class huge {
private:
unsigned char data[BYTES];
public:
void setval(unsigned int);
void setval(const char *);
};
void huge::setval(unsigned int t) {
for(int i = 0; i< BYTES ; i++) {
data[i] = t;
t = t >> 1;
}
}
void huge::setval(const char *s) {
for(int i = 0; i< BYTES ; i++)
data[i] = s[i];
}
int main() {
huge p;
p.setval(0);
return 0;
}
The literal 0 has two meanings in C++.
On the one hand, it is an integer with the value 0.
On the other hand, it is a null-pointer constant.
As your setval function can accept either an int or a char*, the compiler can not decide which overload you meant.
The easiest solution is to just cast the 0 to the right type.
Another option is to ensure the int overload is preferred, for example by making the other one a template:
class huge
{
private:
unsigned char data[BYTES];
public:
void setval(unsigned int);
template <class T> void setval(const T *); // not implemented
template <> void setval(const char*);
};
The solution is very simple if we consider the type of the constant value, which should be "unsigned int" instead of "int".
Instead of:
setval(0)
Use:
setval(0u)
The suffix "u" tell the compiler this is a unsigned integer. Then, no conversion would be needed, and the call will be unambiguous.
replace p.setval(0); with the following.
const unsigned int param = 0;
p.setval(param);
That way it knows for sure which type the constant 0 is.
Use
p.setval(static_cast<const char *>(0));
or
p.setval(static_cast<unsigned int>(0));
As indicated by the error, the type of 0 is int. This can just as easily be cast to an unsigned int or a const char *. By making the cast manually, you are telling the compiler which overload you want.
Cast the value so the compiler knows which function to call:
p.setval(static_cast<const char *>( 0 ));
Note, that you have a segmentation fault in your code after you get it to compile (depending on which function you really wanted to call).
That is ambiguous because a pointer is just an address, so an int can also be treated as a pointer – 0 (an int) can be converted to unsigned int or char * equally easily.
The short answer is to call p.setval() with something that's unambiguously one of the types it's implemented for: unsigned int or char *. p.setval(0U), p.setval((unsigned int)0), and p.setval((char *)0) will all compile.
It's generally a good idea to stay out of this situation in the first place, though, by not defining overloaded functions with such similar types.
I have code which has a lot of conversions from double to int . The code can be seen as
double n = 5.78;
int d = n; // double implicitly converted to a int
The implicit conversion from double to int is that of a truncation which means 5.78 will be saved as 5 . However it has been decided to change this behavior with custom rounding off .
One approach to such problem would be to have your own DOUBLE and INT data types and use conversion operators but alas my code is big and I am not allowed to do much changes . Another approach i thought of was to add 0.5 in each of the numbers but alas the code is big and i was changing too much .
What can be a simple approach to change double to int conversion behaviour which impact the whole code.
You can use uniform initialization syntax to forbid narrowing conversions:
double a;
int b{a}; // error
If you don't want that, you can use std::round function (or its sisters std::ceil/std::floor/std::trunc):
int b = std::round(a);
If you want minimal diff changes, here's what you can do. Please note, though, that this is a bad solution (if it can be named that), and much more likely leaving you crashing and burning due to undefined behavior than actually solving real problems.
Define your custom Int type that handles conversions the way you want it to:
class MyInt
{
//...
};
then evilly replace each occurence of int with MyInt with the help of preprocessor black magic:
#define int MyInt
Problems:
if you accidentally change definitions in the standard library - you're in the UB-land
if you change the return type of main - you're in the UB-land
if you change the definition of a function but not it's forward declarations - you're in the UB/linker error land. Or in the silently-calling-different-overload-land.
probably more.
Do something like this:
#include <iostream>
using namespace std;
int myConvert (double rhs)
{
int answer = (int)rhs; //do something fancier here to meet your needs
return answer;
}
int main()
{
double n = 5.78;
int d = myConvert(n);
cout << "d = " << d << endl;
return 0;
}
You can make myConvert as fancy as you want. Otherwise, you could define your own class for int (e.g. myInt class) and overload the = operator to do the right conversion.
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.
What does this error message mean?
error: call of overloaded ‘setval(int)’ is ambiguous
huge.cpp:18: note: candidates are: void huge::setval(unsigned int)
huge.cpp:28: note: void huge::setval(const char*)
My code looks like this:
#include <iostream>
#define BYTES 8
using namespace std ;
class huge {
private:
unsigned char data[BYTES];
public:
void setval(unsigned int);
void setval(const char *);
};
void huge::setval(unsigned int t) {
for(int i = 0; i< BYTES ; i++) {
data[i] = t;
t = t >> 1;
}
}
void huge::setval(const char *s) {
for(int i = 0; i< BYTES ; i++)
data[i] = s[i];
}
int main() {
huge p;
p.setval(0);
return 0;
}
The literal 0 has two meanings in C++.
On the one hand, it is an integer with the value 0.
On the other hand, it is a null-pointer constant.
As your setval function can accept either an int or a char*, the compiler can not decide which overload you meant.
The easiest solution is to just cast the 0 to the right type.
Another option is to ensure the int overload is preferred, for example by making the other one a template:
class huge
{
private:
unsigned char data[BYTES];
public:
void setval(unsigned int);
template <class T> void setval(const T *); // not implemented
template <> void setval(const char*);
};
The solution is very simple if we consider the type of the constant value, which should be "unsigned int" instead of "int".
Instead of:
setval(0)
Use:
setval(0u)
The suffix "u" tell the compiler this is a unsigned integer. Then, no conversion would be needed, and the call will be unambiguous.
replace p.setval(0); with the following.
const unsigned int param = 0;
p.setval(param);
That way it knows for sure which type the constant 0 is.
Use
p.setval(static_cast<const char *>(0));
or
p.setval(static_cast<unsigned int>(0));
As indicated by the error, the type of 0 is int. This can just as easily be cast to an unsigned int or a const char *. By making the cast manually, you are telling the compiler which overload you want.
Cast the value so the compiler knows which function to call:
p.setval(static_cast<const char *>( 0 ));
Note, that you have a segmentation fault in your code after you get it to compile (depending on which function you really wanted to call).
That is ambiguous because a pointer is just an address, so an int can also be treated as a pointer – 0 (an int) can be converted to unsigned int or char * equally easily.
The short answer is to call p.setval() with something that's unambiguously one of the types it's implemented for: unsigned int or char *. p.setval(0U), p.setval((unsigned int)0), and p.setval((char *)0) will all compile.
It's generally a good idea to stay out of this situation in the first place, though, by not defining overloaded functions with such similar types.