I have a templated class which has many member variables. A small number of these variables have the template type of the class, the majority have fixed types.
I'd like to copy between one instance of the class to another with conversions, but cannot do so using implicit copy if the classes do not have the same type. Therefore, I need an assignment method.
However, it feels unfortunate to have to write out all of those many copy operations just to do the conversion I want.
Therefore, is there a way to set up the assignment operator such that implicit copies are done where possible?
An example code follows:
#include <iostream>
template<class T>
class MyClass {
public:
int a,b,c,d,f; //Many, many variables
T uhoh; //A single, templated variable
template<class U>
MyClass<T>& operator=(const MyClass<U>& o){
a = o.a; //Many, many copy operations which
b = o.b; //could otherwise be done implicitly
c = o.c;
d = o.d;
f = o.f;
uhoh = (T)o.uhoh; //A single converting copy
return *this;
}
};
int main(){
MyClass<int> a,b;
MyClass<float> c;
a.uhoh = 3;
b = a; //This could be done implicitly
std::cout<<b.uhoh<<std::endl;
c = a; //This cannot be done implicitly
std::cout<<c.uhoh<<std::endl;
}
There are 2 naïve ways:
Create a function CopyFrom(const MyClass& o) that copy the copiable values
then you call it from the operator= overload plus eventually template specialization depending on your needs.
Pack all the copiable values in a subclass/struct, you'll be able to use the default operator= generated by your compiler ;)
Related
Consider the following code :
template <class T>
T average(T *atArray, int nNumValues)
{
T tSum = 0;
for (int nCount = 0; nCount < nNumValues; nCount++)
{
tSum += atArray[nCount];
}
tSum = tSum / nNumValues;
return tSum;
}
And the following question on it :
Which of the following statements about the class/type T must be true in order for the code to compile and run without crashing?
It must be some kind of numeric type
Must have < operator-defined
Must have the [ ] access operator-defined
Must have copy constructor and assignment operator
My Thoughts:
I think it could be something apart from numeric type but it will need to have the operator + and / well defined.
point 2 seems incorrect as < has no relation with / and + operator
same with point 3 and point 4.
Although I am not sure about my reasoning above.
No - It could for example do implicit conversions to/from a numeric type and have operator+= defined.
No - That operator is not used on a T
No - That operator is not used on a T, only a T* and pointer types all have this operator defined.
No - The copy constructor can be deleted and the question says "and" so the answer is no. It needs some kind of assignment operator though.
Consider this class, especially constructed to be able to answer no to as many questions as possible:
struct foo {
foo() = default;
foo(int) {} // implicit conversion from int
foo(const foo&) = delete; // no copy constructor
foo(foo&&) = default; // but move constructor
foo& operator=(const foo&) = delete; // no copy assignment
foo& operator=(foo&&) = delete; // no move assignment
foo& operator=(int) { return *this; }; // but assignment from int
foo& operator+=(const foo&) { return *this; } // for tSum += atArray[nCount];
operator int() const { return 1; } // implicit conversion to int
};
And it would work fine with the function template:
int main() {
foo arr[2];
auto x = average(arr, 2);
}
A class type with sufficient overloaded operators (like std::complex<double>) could work.
The < is only used on int expressions, not involving T.
The atArray[nCount] expression uses a T* pointer, not an expression with type T, so it has the built-in meaning.
Technically no, since fundamental types don't have constructors or assignment operators at all, just similar semantics. Also, technically every class type "has" a copy constructor and assignment operator, even if deleted. Another issue: T could be a class with normal assignment operator, deleted copy constructor, and public non-deleted move constructor.
Probably the intended answer is #4.
The actual requirements on T are:
A variable of type T can be copy-initialized from an int, or from a null pointer constant. (0 is a special expression which can do two different things...)
T is a numeric type, or an enumeration or class type with valid operator functions supporting expressions:
a += b and a = b, where a and b are lvalues of type T
a / n, where a is an lvalue of type T and n is an lvalue of type int
T is move-constructible.
Consider this simple example:
template <class Type>
class smartref {
public:
smartref() : data(new Type) { }
operator Type&(){ return *data; }
private:
Type* data;
};
class person {
public:
void think() { std::cout << "I am thinking"; }
};
int main() {
smartref<person> p;
p.think(); // why does not the compiler try substituting Type&?
}
How do conversion operators work in C++? (i.e) when does the compiler try substituting the type defined after the conversion operator?
Some random situations where conversion functions are used and not used follow.
First, note that conversion functions are never used to convert to the same class type or to a base class type.
Conversion during argument passing
Conversion during argument passing will use the rules for copy initialization. These rules just consider any conversion function, disregarding of whether converting to a reference or not.
struct B { };
struct A {
operator B() { return B(); }
};
void f(B);
int main() { f(A()); } // called!
Argument passing is just one context of copy initialization. Another is the "pure" form using the copy initialization syntax
B b = A(); // called!
Conversion to reference
In the conditional operator, conversion to a reference type is possible, if the type converted to is an lvalue.
struct B { };
struct A {
operator B&() { static B b; return b; }
};
int main() { B b; 0 ? b : A(); } // called!
Another conversion to reference is when you bind a reference, directly
struct B { };
struct A {
operator B&() { static B b; return b; }
};
B &b = A(); // called!
Conversion to function pointers
You may have a conversion function to a function pointer or reference, and when a call is made, then it might be used.
typedef void (*fPtr)(int);
void foo(int a);
struct test {
operator fPtr() { return foo; }
};
int main() {
test t; t(10); // called!
}
This thing can actually become quite useful sometimes.
Conversion to non class types
The implicit conversions that happen always and everywhere can use user defined conversions too. You may define a conversion function that returns a boolean value
struct test {
operator bool() { return true; }
};
int main() {
test t;
if(t) { ... }
}
(The conversion to bool in this case can be made safer by the safe-bool idiom, to forbid conversions to other integer types.) The conversions are triggered anywhere where a built-in operator expects a certain type. Conversions may get into the way, though.
struct test {
void operator[](unsigned int) { }
operator char *() { static char c; return &c; }
};
int main() {
test t; t[0]; // ambiguous
}
// (t).operator[] (unsigned int) : member
// operator[](T *, std::ptrdiff_t) : built-in
The call can be ambiguous, because for the member, the second parameter needs a conversion, and for the built-in operator, the first needs a user defined conversion. The other two parameters match perfectly respectively. The call can be non-ambiguous in some cases (ptrdiff_t needs be different from int then).
Conversion function template
Templates allow some nice things, but better be very cautious about them. The following makes a type convertible to any pointer type (member pointers aren't seen as "pointer types").
struct test {
template<typename T>
operator T*() { return 0; }
};
void *pv = test();
bool *pb = test();
The "." operator is not overloadable in C++. And whenever you say x.y, no conversion will automatically be be performed on x.
Conversions aren't magic. Just because A has a conversion to B and B has a foo method doesn't mean that a.foo() will call B::foo().
The compiler tries to use a conversion in four situations
You explicitly cast a variable to another type
You pass the variable as an argument to a function that expects a different type in that position (operators count as functions here)
You assign the variable to a variable of a different type
You use the variable copy-construct or initialize a variable of a different type
There are three types of conversions, other than those involved with inheritance
Built-in conversions (e.g. int-to-double)
Implicit construction, where class B defines a constructor taking a single argument of type A, and does not mark it with the "explicit" keyword
User-defined conversion operators, where class A defines an operator B (as in your example)
How the compiler decides which type of conversion to use and when (especially when there are multiple choices) is pretty involved, and I'd do a bad job of trying to condense it into an answer on SO. Section 12.3 of the C++ standard discusses implicit construction and user-defined conversion operators.
(There may be some conversion situations or methods that I haven't thought of, so please comment or edit them if you see something missing)
Implicit conversion (whether by conversion operators or non-explicit constructors) occurs when passing parameters to functions (including overloaded and default operators for classes). In addition to this, there are some implicit conversions performed on arithmetic types (so adding a char and a long results in the addition of two longs, with a long result).
Implicit conversion does not apply to the object on which a member function call is made: for the purposes of implicit conversion, "this" is not a function parameter.
The compiler will attempt one(!) user-defined cast (implicit ctor or cast operator) if you try to use an object (reference) of type T where U is required.
The . operator, however, will always try to access a member of the object (reference) on its left side. That's just the way it's defined. If you want something more fancy, that's what operator->() can be overloaded for.
You should do
((person)p).think();
The compiler doesn't have the information for automatically casting to person, so you need explicit casting.
If you would use something like
person pers = p;
Then the compiler has information for implicit casting to person.
You can have "casting" through constructors:
class A
{
public:
A( int );
};
A a = 10; // Looks like a cast from int to A
These are some brief examples. Casting (implicit, explicit, etc) needs more to explain. You can find details in serious C++ books (see the questions about C++ books on stack overflow for good titles, like this one).
//Virtual table Fuction(VFT)
#include <iostream>
using namespace std;
class smartref {
public:
virtual char think() { }//for Late bindig make virtual function if not make virtual function of char think() {} then become early binding and pointer call this class function
smartref() : data(new char) { }
operator char(){ return *data; }
private:
char* data;
};
class person:public smartref
{
public:
char think() { std::cout << "I am thinking"; }
};
int main() {
smartref *p;//make pointer of class
person o1;//make object of class
p=&o1;//store object address in pointer
p->think(); // Late Binding in class person
return 0;
}
Probably this has been asked and answered already, but I don't know what to search for.
Can move semantics be used for non-pointer data members, if the data members have move assignment operators defined?
Suppose I have a class M that defines M::operator=(M&&) like this:
template <class T>
class M
{
public:
M()
{
mem_M = new T;
}
M& operator=(M&& src)
{
if (this != &src)
{
mem_M = src.mem_M;
src.mem_M = nullptr;
}
return *this;
}
private:
T* mem_M;
};
Now obviously I can have a class C<T> like this, with a move constructor that makes no use of T's move assignment operator:
template <class T>
class C
{
public:
C ()
{
mem_C = new T;
}
C (C&& rhs)
{
mem_C = rhs.mem_C;
rhs.mem_C = nullptr;
}
private:
T* mem_C;
};
However, what if I wanted C<T>::mem_C to not be a pointer but an ordinary member, how would I deal with C<T>::mem_C in the move-functions? I can of course invoke the move assignment operator T::operator=(T&&) to move the filed mem_C from one instance to the other, but how do I properly reset the instance of C passed to C<T>::C(C&&)?
This at least looks wrong to me:
template <class T>
class C
{
public:
C ()
{
mem_C = T();
}
C (C<T>&& rhs)
{
mem_C = std::move(rhs.mem_C);
rhs.mem_C = T(); // ?? like this?
}
private:
T mem_C;
};
So, what is the standard compliant way to reset non-pointer data members in move functions?
The move assignment/constructors for the contained types must leave the objects in an "acceptable" state, whatever that means for that type. Nothing outside the type being moved should have any responsibility for maintaining the state of the object.
Also, you want to make sure you're calling move constructors of contained types in your parent move constructor, not the contained type's move assignment as you are in your example:
// move constructor calls move constructor of contained elements
C (C<T>&& rhs) : mem_c(std::move(rhs.mem_c))
{
// anything in here is using already-constructed data members
}
// move assignment calls move assignment of contained elements
C & operator=(C<T>&& rhs) {
mem_c = std::move(rhs.mem_c);
}
Consider this simple example:
template <class Type>
class smartref {
public:
smartref() : data(new Type) { }
operator Type&(){ return *data; }
private:
Type* data;
};
class person {
public:
void think() { std::cout << "I am thinking"; }
};
int main() {
smartref<person> p;
p.think(); // why does not the compiler try substituting Type&?
}
How do conversion operators work in C++? (i.e) when does the compiler try substituting the type defined after the conversion operator?
Some random situations where conversion functions are used and not used follow.
First, note that conversion functions are never used to convert to the same class type or to a base class type.
Conversion during argument passing
Conversion during argument passing will use the rules for copy initialization. These rules just consider any conversion function, disregarding of whether converting to a reference or not.
struct B { };
struct A {
operator B() { return B(); }
};
void f(B);
int main() { f(A()); } // called!
Argument passing is just one context of copy initialization. Another is the "pure" form using the copy initialization syntax
B b = A(); // called!
Conversion to reference
In the conditional operator, conversion to a reference type is possible, if the type converted to is an lvalue.
struct B { };
struct A {
operator B&() { static B b; return b; }
};
int main() { B b; 0 ? b : A(); } // called!
Another conversion to reference is when you bind a reference, directly
struct B { };
struct A {
operator B&() { static B b; return b; }
};
B &b = A(); // called!
Conversion to function pointers
You may have a conversion function to a function pointer or reference, and when a call is made, then it might be used.
typedef void (*fPtr)(int);
void foo(int a);
struct test {
operator fPtr() { return foo; }
};
int main() {
test t; t(10); // called!
}
This thing can actually become quite useful sometimes.
Conversion to non class types
The implicit conversions that happen always and everywhere can use user defined conversions too. You may define a conversion function that returns a boolean value
struct test {
operator bool() { return true; }
};
int main() {
test t;
if(t) { ... }
}
(The conversion to bool in this case can be made safer by the safe-bool idiom, to forbid conversions to other integer types.) The conversions are triggered anywhere where a built-in operator expects a certain type. Conversions may get into the way, though.
struct test {
void operator[](unsigned int) { }
operator char *() { static char c; return &c; }
};
int main() {
test t; t[0]; // ambiguous
}
// (t).operator[] (unsigned int) : member
// operator[](T *, std::ptrdiff_t) : built-in
The call can be ambiguous, because for the member, the second parameter needs a conversion, and for the built-in operator, the first needs a user defined conversion. The other two parameters match perfectly respectively. The call can be non-ambiguous in some cases (ptrdiff_t needs be different from int then).
Conversion function template
Templates allow some nice things, but better be very cautious about them. The following makes a type convertible to any pointer type (member pointers aren't seen as "pointer types").
struct test {
template<typename T>
operator T*() { return 0; }
};
void *pv = test();
bool *pb = test();
The "." operator is not overloadable in C++. And whenever you say x.y, no conversion will automatically be be performed on x.
Conversions aren't magic. Just because A has a conversion to B and B has a foo method doesn't mean that a.foo() will call B::foo().
The compiler tries to use a conversion in four situations
You explicitly cast a variable to another type
You pass the variable as an argument to a function that expects a different type in that position (operators count as functions here)
You assign the variable to a variable of a different type
You use the variable copy-construct or initialize a variable of a different type
There are three types of conversions, other than those involved with inheritance
Built-in conversions (e.g. int-to-double)
Implicit construction, where class B defines a constructor taking a single argument of type A, and does not mark it with the "explicit" keyword
User-defined conversion operators, where class A defines an operator B (as in your example)
How the compiler decides which type of conversion to use and when (especially when there are multiple choices) is pretty involved, and I'd do a bad job of trying to condense it into an answer on SO. Section 12.3 of the C++ standard discusses implicit construction and user-defined conversion operators.
(There may be some conversion situations or methods that I haven't thought of, so please comment or edit them if you see something missing)
Implicit conversion (whether by conversion operators or non-explicit constructors) occurs when passing parameters to functions (including overloaded and default operators for classes). In addition to this, there are some implicit conversions performed on arithmetic types (so adding a char and a long results in the addition of two longs, with a long result).
Implicit conversion does not apply to the object on which a member function call is made: for the purposes of implicit conversion, "this" is not a function parameter.
The compiler will attempt one(!) user-defined cast (implicit ctor or cast operator) if you try to use an object (reference) of type T where U is required.
The . operator, however, will always try to access a member of the object (reference) on its left side. That's just the way it's defined. If you want something more fancy, that's what operator->() can be overloaded for.
You should do
((person)p).think();
The compiler doesn't have the information for automatically casting to person, so you need explicit casting.
If you would use something like
person pers = p;
Then the compiler has information for implicit casting to person.
You can have "casting" through constructors:
class A
{
public:
A( int );
};
A a = 10; // Looks like a cast from int to A
These are some brief examples. Casting (implicit, explicit, etc) needs more to explain. You can find details in serious C++ books (see the questions about C++ books on stack overflow for good titles, like this one).
//Virtual table Fuction(VFT)
#include <iostream>
using namespace std;
class smartref {
public:
virtual char think() { }//for Late bindig make virtual function if not make virtual function of char think() {} then become early binding and pointer call this class function
smartref() : data(new char) { }
operator char(){ return *data; }
private:
char* data;
};
class person:public smartref
{
public:
char think() { std::cout << "I am thinking"; }
};
int main() {
smartref *p;//make pointer of class
person o1;//make object of class
p=&o1;//store object address in pointer
p->think(); // Late Binding in class person
return 0;
}
Two questions about the following piece of code:
template <class T> class A {
protected:
T j;
public:
A(T k) :j(k) {cout << *this;}
~A() { cout << *this; }
A(const A<T> &a) {
j = a.j;
cout << *this;
}
virtual void print() const {cout << j << ' ';}
friend ostream &operator << (ostream &os, const A<T> &a) {
a.print();
return os;
}
operator T() { return j;}
};
template <class T> class inherit:public A<T> {
T field;
public:
inherit(const T&t) :A<T>(t), field(1+t) {
cout << *this;
}
void print() const {
A<T>::print();
cout << field << ' ';
}
};
int main(){
inherit <int> b(3);
inherit <string> c("asdf");
string k="str";
c + k;//error no operator +
b + 5;//no error
}
Why does inherit <int> b(3); leads to the copy ctor of inherit? Why copy instead of making a new instance of inherit from scratch using the default ctor?
Why does b+5; leads to the conversion operator operator T() and why it doesn't happen with c+k?
Why does inherit <int> b(3); leads to the copy ctor of inherit? Why copy instead of making a new instance of inherit from scratch using the default ctor?
Firstly, it does not lead to the copy constructor and the instance is in fact made from scratch.
The default constructor was not used because you didn't call the default constructor. The default constructor would be called with empty argument list (except, in this case, you must also leave out the parenthesis to avoid the vexing parse):
inherit <int> b; // this would call the default constructor
If you pass an argument to the constructor, then a non-default constructor will be invoked. inherit <int> b(3); leads to a call to inherit(const T&) which in this template instance is inherit(const int&). It is not the copy constructor of inherit.
Why does b+5; leads to the casting operator operator T()
Because there is no operator+(const inherit<int>&, int) nor the analogous member function defined. Therefore, the overload resolution looks for alternatives to which the operands can be implicitly converted. It just so happens, that a built-in operator+(int, int) exists, and inherit<int> can implicitly be converted to A<int> (because it's a base) and A<int> can be converted to an int (because of the casting operator). And so, that operator ends up being called.
and why it doesn't happen with c+k?
Firstly, you cannot even instantiate inherit <string> because the constructor tries to add an int to the argument string, which has no valid overload.
Now, assuming that constructor was fixed so that inherit<string> can exist, c + k still doesn't seem to work. I suspect that's because the string needs more conversions than int because it's not a primitive and you've reached the maximum depth that a user-defined conversion sequence can have. You can explicitly cast inherit<string> to string to shorten the conversion sequence:
static_cast<std::string>(c) + k; // this works
Why does b+5; leads to the conversion operator operator T() and why it doesn't happen with c+k?
The compiler is complaining about a completely different piece of code. If you remove the + inside main(), you can see it still complains about an operator+:
http://melpon.org/wandbox/permlink/H3cUUaf8fSnbYDwA
The reason for this is on this line:
inherit(const T&t) :A<T>(t), field(1+t) {
you have 1 + t, where t is std::string. std::string has no operator+ for int, so this does not compile.