I have the following non-type template:
template<size_t MAX_SIZE>
struct Path{
struct Point{
float x;
float y;
}
};
Point segment[MAX_SIZE];
};
If I now declare two different Paths, I cannot assign elements of the different segments to each other, as the structs may have the same structure, but are of different type :
Path<10> path_a ;
Path<30> path_b ;
path_a.segment[0].x = 1;
path_a.segment[0].y = 2;
path_b.segment[0] = path_a.segment[0]; // <- error C2679 in Visual Studio)
Of course, if I separate the definition of Point and Path, the assignment would work:
struct Point{
float x;
float y;
};
template<size_t MAX_SIZE>
struct Path{
Point segment[MAX_SIZE];
};
But that's not what I want (this is just a MWE), so I was wondering how I can overload the copy assignment operator to make it work. I've tried numerous variants, for example:
template<size_t MAX_SIZE>
struct Path{
struct Point{
float x;
float y;
template<size_t OTHER_SIZE>
Point & operator = (const typename Path<OTHER_SIZE>::Point & that)
{
x = that.x;
y = that.y;
return *this;
}
};
Point segment[MAX_SIZE];
};
but I always get the same error. So my question is: Is it possible to overload = in a way that allows for an assignment of the following form without changing the layout of my structs?
path_b.segment[0] = path_a.segment[0];
Overloading the assignment operator (operator=) is fairly straightforward, with one specific caveat that we'll get to. The assignment operator must be overloaded as a member function. This will call f1. operator=(f1), and under the simplistic implementation above, all of the members will be assigned to themselves.
A trivial copy assignment operator makes a copy of the object representation as if by std::memmove. All data types compatible with the C language (POD types) are trivially copy-assignable.
In a simple words, Copy constructor is called when a new object is created from an existing object, as a copy of the existing object. And assignment operator is called when an already initialized object is assigned a new value from another existing object.
The Copy constructor and the assignment operators are used to initializing one object to another object. The main difference between them is that the copy constructor creates a separate memory block for the new object. But the assignment operator does not make new memory space.
Yes, such setup is possible. At the core, you need an assignment operator template which will accept all types:
template<class T>
Point & operator = (const T & that)
As a basic solution, this would be enough. It will now work with all types which have members x
and y
of compatible types, and produce a (usually) ugly error message for types which don't.
If that's good enough for you, we're done.
If you have other overloads of the assignment operator, you will probably want to selectively disable the template one. For this, you will need to instrument the Point
classes and use SFINAE:
template<size_t MAX_SIZE>
struct Path{
struct Point{
float x;
float y;
struct EnableAssignment {};
};
Point segment[MAX_SIZE];
};
The instrumentation is then used like this:
template<class T, class U = typename T::EnableAssignment>
Point & operator = (const T & that)
[Simplified live example]
The code above uses a default template argument in a function template, which was only introduced in C++11. Before that, you would have to invoke SFINAE in some other way:
template <class L, class R>
struct SfinaeThenRight
{
typedef R type;
};
template <class T>
typename SfinaeThenRight<typename T::EnableAssignment, Point&>::type operator = (const T & that)
[Simplified C++98 live example]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With