Class object as float type - c++

I have a class MyFloat:
class MyFloat
{
public:
float value = 0.0;
}
I use it so far in this way:
MyFloat *myfloat1 = new MyFloat;
myfloat1->value = 1.0;
How can I make
myfloat1 = 2.0;
if (myfloat1 < 3.0){
...
}

You can use operator= and operator float
class MyFloat
{
public:
float value = 0.0;
MyFloat& operator=(float f)
{
value = f;
return *this;
}
operator float() const
{
return value;
}
};
int main() {
MyFloat f;
f = 10.0f;
float x;
x = f;
return 0;
}

As others have mentiond you could provide a operator=(float), however for a MyFloat it is more natural to be constructed with a float instead of first constructing it and then assigning a value:
class MyFloat {
public:
float value = 0.0;
MyFloat(float x) : value(x) {}
MyFloat() {}
};
int main() {
MyFloat x;
x = 1.0; // works because MyFloat(float) is used
MyFloat y(2.0); // this is nicer
}
PS: as pointed out by R2RT, for x = 1.0; you dont want to use the constructor, but an assignment operator (I just left the line because thats what you were asking for). However, for a newly constructed MyFloat I would always prefer to pass the value to the constructor.

Your object is of type MyFloat, not float so you can't assign a float value to it. What you can do is assign a float value to a data member of your class by overriding the class' = assignment operator:
MyFloat& operator=(float p) {
value = p;
return *this;
}

Related

How to update multiple fields of a struct simultaneously?

Let's say I have a struct
struct Vector3 {
float x;
float y;
float z;
};
Note that sizeof(Vector3) must remain the same.
EDIT: I am interested in solutions without setters.
Not let's create an instance of that struct Vector3 pos . How can I implement my struct so I can have something like this pos.xy = 10 // updates x and y or pos.yz = 20 // updates y and z or pos.xz = 30 // updates x and z?
Here is a solution that has the desired syntax, and doesn't increase the size of the class. It is technically correct, but rather convoluted:
union Vector3 {
struct {
float x, y, z;
auto& operator=(float f) { x = f; return *this; }
operator float&() & { return x; }
operator const float&() const & { return x; }
operator float () && { return x; }
float* operator&() { return &x; }
} x;
struct {
float x, y, z;
auto& operator=(float f) { y = f; return *this; }
operator float&() & { return y; }
operator const float&() const & { return y; }
operator float () && { return y; }
float* operator&() { return &y; }
} y;
struct {
float x, y, z;
auto& operator=(float f) { z = f; return *this; }
operator float&() & { return z; }
operator const float&() const & { return z; }
operator float () && { return z; }
float* operator&() { return &z; }
} z;
struct {
float x, y, z;
auto& operator=(float f) { x = y = f; return *this; }
} xy;
struct {
float x, y, z;
auto& operator=(float f) { y = z = f; return *this; }
} yz;
struct {
float x, y, z;
auto& operator=(float f) { z = x = f; return *this; }
} zx;
};
Another which relies on owner_of implemented here: https://gist.github.com/xymopen/352cbb55ddc2a767ed7c5999cfed4d31 which probably depends on some technically implementation specific (possibly undefined) behaviour:
struct Vector3 {
float x;
float y;
float z;
[[no_unique_address]]
struct {
auto& operator=(float f) {
Vector3* v = owner_of(this, &Vector3::xy);
v->x = v->y = f;
return *this;
}
} xy;
[[no_unique_address]]
struct {
auto& operator=(float f) {
Vector3* v = owner_of(this, &Vector3::yz);
v->y = v->z = f;
return *this;
}
} yz;
[[no_unique_address]]
struct {
auto& operator=(float f) {
Vector3* v = owner_of(this, &Vector3::zx);
v->z = v->x = f;
return *this;
}
} zx;
[[no_unique_address]]
struct {
auto& operator=(float f) {
Vector3* v = owner_of(this, &Vector3::zx);
v->x = v->y = v->z = f;
return *this;
}
} xyz;
};
The simple way is to provide setters for the combinations you want to set:
struct Vector3 {
float x = 0;
float y = 0;
float z = 0;
void set_xy(float v) {
x = v;
y = v;
}
};
int main(){
Vector3 pos;
pos.set_xy(42);
}
And if you need sizeof(Vector3) to stay the same, thats the only way.
Just "for fun" this is how you can get pos.set_xy = 20; literally:
struct two_setter {
float& one;
float& two;
void operator=(float v){
one = v;
two = v;
}
};
struct Vector3 {
float x = 0;
float y = 0;
float z = 0;
two_setter set_xy{x,y};
};
int main(){
Vector3 pos;
pos.set_xy = 42;
}
However, it has severe downsides. First it can have almost twice the size of the original Vector3. Moreover, because the two_setter stores references, Vector3 cannot be copied. If it would store pointers, copying would be possible, but then even more code would be required to get it right.
Alternatively it is possible to provide a xy method that returns a proxy that assigns the two members. But I am not going into detail, because pos.xy() = 3; looks really odd, has no advantage to pos.xy(3) and you really should provide a setter (or just rely on the user making two assignments when they want to make two assignments ;).
TL;DR Use a method instead of trying to get a syntax that C++ does not support out of the box.
It is possible to create an empty struct inside Vector3 with an operator=() that sets the variables of the outer struct. Of course for a variable to really take no space itself, you have to use [[no_unique_address]], which is only available since C++20. But here is an example of how it might work:
struct Vector3 {
[[no_unique_address]] struct {
auto &operator=(float val) {
Vector3 *self = (Vector3 *)(this);
self->x = val;
self->y = val;
return *this;
}
} xy;
// Add similar code for xz and yz
float x;
float y;
float z;
};
See it running on godbolt.org.
Since your type is standard-layout, I think the only legal way to do this, as per the C++ standard, is with a union that contains sub-objects with custom operator= definitions.
With a union, you're allowed to view the common-initial sequence of the active member, provided all types are standard-layout types. So if we carefully craft an object that shares the same common members (e.g. 3 float objects in the same order), then we can "swizzle" between them without violating strict-aliasing.
For us to accomplish this, we will need to create a bunch of members that all have the same data in the same order, in standard-layout type.
As a simple example, lets create a basic proxy type:
template <int...Idx>
class Vector3Proxy
{
public:
// ...
template <int...UIdx,
typename = std::enable_if_t<(sizeof...(Idx)==sizeof...(UIdx))>>
auto operator=(const Vector3Proxy<UIdx...>& other) -> Vector3Proxy&
{
((m_data[Idx] = other.m_data[UIdx]),...);
return (*this);
}
auto operator=(float x) -> Vector3Proxy&
{
((m_data[Idx] = x),...);
return (*this);
}
// ...
private:
float m_data[3];
template <int...> friend class Vector3Proxy;
};
In this example, not all members of m_data are used -- but they exist so that the "common-initial sequence" requirement is satisfied, which will allow us to view it through other standard-layout types within the union.
This can be built up as much as you need; float conversion for single-component operators, support for arithmetic, etc.
With a type like this, we can now build a Vector3 objects out of these proxy types
struct Vector3
{
union {
float _storage[3]; // for easy initialization
Vector3Proxy<0> x;
Vector3Proxy<1> y;
Vector3Proxy<2> z;
Vector3Proxy<0,1> xy;
Vector3Proxy<1,2> yz;
Vector3Proxy<0,2> xz;
// ...
};
};
Then the type can easily be used to assign to multiple values at once:
Vector3 x = {1,2,3};
x.xy = 5;
Or to assign components of one part to another:
Vector3 a = {1,2,3};
Vector3 b = {4,5,6};
a.xy = b.yz; // produces {5,6,3}
Live Example
This solution also ensures that sizeof(Vector3) does not change, since all proxy objects are the same size.
Note: It's not valid in C++ to use a union with anonymous structs, though some compilers support it. So although it might be tempting to rewrite this like:
union {
struct {
float x;
float y;
float z;
}; // invalid, since this is anonymous
struct {
...
} xy;
}
This is not valid in standard C++, and would not be a portable solution.
How can I implement my struct so I can have something like this pos.xy = 10 // updates x and y or pos.yz = 20 // updates y and z or pos.xz = 30 // updates x and z?
Just add the necessary class member functions to do this:
struct Vector3 {
float x;
float y;
float z;
void update_xy(float value) { x = y = value; }
void update_yz(float value) { y = z = value; }
void update_xz(float value) { x = z = value; }
};

Is there a way to modify 'operator->' so that 'z->im' returns imaginary part of complex number

I have a struct Cmplx which models complex numbers.
class Cmplx{
double x;
double y;
public:
Cmplx(int X, int Y){x = X; y = Y;}
double& operator->(...){...}
}
I need to implement the operator, such that
int main(){
Cmlpx z(1,2);
z->im = 5;
z->re = 2;
}
Changes my complex number into (2,5); I know how to do it when im and re are strings, but have no idea how to do it like this.
You might abuse of operator-> that way:
struct ComplexRef
{
ComplexRef* operator->() { return this;}
double& re;
double& im;
};
class Cmplx{
double x;
double y;
public:
Cmplx(int X, int Y){x = X; y = Y;}
ComplexRef operator->(){ return {x, y}; }
};
Demo
The overload of operator -> must either return a raw pointer, or return an object (by reference or by value) for which operator -> is in turn overloaded.

Overloading = operator in c++ with float argument

I have the following program:
#include <iostream>
using namespace std;
class N {
public:
float x;
N(){ x = 3.0; }
N(float y){ x = y; }
N &operator=(float f){ return *new N(f); }
};
int main(){
N a;
a = 2.0;
cout << a.x;
return 0;
}
I am expecting for the result to be 2 (because of definition of operator=), but instead it gives me 3 (like there is no line a = 2.0). Can someone, please, explain me why is this happening, what is wrong with definition of 'operator='? Thank you...
Your copy assignment operator should be setting the value of x, then returning a reference to *this, like so:
N &operator =(float f) { x = f; return *this; }
Instead, your copy assignment operator is constructing a new instance of N on the heap, and returning a reference to that.
You shouldn't use new, C++ isn't java.
N& operator=(float f)
{
x = f;
return *this;
}
Try this.

Overload Function Call Operator in a Class

In the .h file given to me by my professor, he's written
double operator()(double x) const;
The point of the overload is to read in x as a double and use it to evaluate a polynomial that's stored in the class object Term. What I've come up with in the class implementation is
double operator()(double x) const
{ double result = 0.0;
for (int i = 0; i < getSize(); i++)
result += (getCoeff(i) * pow(x, getExponent(i)));
return result;
}
How do I call it from the application? I've tried different calls like
Polynomial p;
p.operator(x);
or
Polynomial::operator(x);
or
operator(x);
but always get errors when compiling.
The usual form is to call it as if your instance was a function:
double x = 3.1416;
Polynomial p;
double y = p(x);
Alternatively, you can explicitly call the operator:
double x = 3.1416;
Polynomial p;
double y = p.operator()(x);
Here's a simplified example:
#include <iostream>
struct Foo
{
double operator()(double x) const { return x*2; }
};
int main()
{
Foo f;
std::cout << f(2.5) << std::endl;
}

How can I build this typ of class interface

I am interested in trying something where I create a custom type and then access to its members using dot semantics. For example:
Class A{ //simplified, omitting constructors and other methods
private:
float numbers[3];
public:
float x(){ return numbers[0]; }
float y(){ return numbers[1]; }
float z(){ return numbers[2]; }
}
So I can do something like this:
A a;
//do stuff to populate `numbers`
float x=a.x;
But I would also like to make the elements in numbers lvalues so I can do something like this:
A a;
a.y=5; //assigns 5 to numbers[1]
How can I do this setting method?
You can return a reference to allow assignment:
float & x(){ return numbers[0]; }
^
// usage
A a;
a.x() = 42;
You should also have a const overload, to allow read-only access to a const object:
float x() const {return numbers[0];}
^^^^^
// usage
A const a = something();
float x = a.x();
First. You made functions x, y and z but assigning them to float. This wouldn't work.
Second. Change these functions to return referencies:
class A{ //simplified, omitting constructors and other methods
private:
float numbers[3];
public:
float & x(){ return numbers[0]; }
float & y(){ return numbers[1]; }
float & z(){ return numbers[2]; }
};
...
A point;
float x = point.x();
point.x() = 42.0f;
There's another way: declare referencies as a members of class and initialize them in c-tor:
class A{ //simplified, omitting constructors and other methods
private:
float numbers[3];
public:
float & x;
float & y;
float & z;
A() : x( numbers[ 0 ] ), y( numbers[ 1 ] ), z( numbers[ 2 ] ) {}
};
...
A point;
float x = point.x;
point.x = 42.0f;
P.S. Pay an attention on comment, that gave #MikeSeymour
Not unless you actually have public variables named x, y and z.
Or you can return a reference and then do a.y() = 5