In some C++ code, I am encountering a compile-time error that seems like it might be indicating that I am trying to reseat a reference. But I feel quite sure that I am not trying to reseat a reference. I do not understand the cause of the error. Perhaps I am being silly, and missing something obvious. Or perhaps the problem reflects deep principles of C++ template programming that I do not adequately understand. Either way, I hope some of you can help. This is the code:
// p.cpp - slimmed down demonstration of error in prop.cpp
template<class T>
class Property {
protected:
T& value;
public:
explicit Property(T& a) : value(a) { }
// default "copy" setter
virtual Property<T>& operator=(T a) { value = a; return *this; }
// default "copy" getter
virtual operator T() const { return value; }
template<class U> // must invoke U virtual getter and T virtual setter
Property<T>& operator=(const Property<U>& newval)
{ return (*this = U(newval)); }
/* // uncommenting this eliminates the error
Property<T>& operator=(const Property<T>& newval)
{ return (*this = T(newval)); }
/**/
};
int main()
{
//* // this code produces the error
{
int i_ = 10, j_;
Property<int> i (i_), j (j_);
j = i;
}
/**/
/* // this code does NOT produce the error
{
int i_ = 10;
long j_;
Property<int> i (i_);
Property<long> j (j_);
j = i;
}
/**/
return 0;
}
When I compile this with gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1 using the command g++ -o p p.cpp I get this output:
p.cpp: In member function ‘Property<int>& Property<int>::operator=(const Property<int>&)’:
p.cpp:4:7: error: non-static reference member ‘int& Property<int>::value’, can’t use default assignment operator
p.cpp: In function ‘int main()’:
p.cpp:33:13: note: synthesized method ‘Property<int>& Property<int>::operator=(const Property<int>&)’ first required here
Before you tell me that I am trying to reseat a reference, please keep in mind that:
-
Uncommenting the definition for
Property::operator=that explicitly takes the same constructed type on the right side as the constructed type on the left side eliminates the error. So the problem is not, per se, thatProperty<int>::valueis being accessed through*this. -
Independently, as shown in
main(), theoperator=method template inside thePropertyclass template is instantiated and works fine when the data type of the value on the right side of=is different from the data type on the left side of=. -
valueis a reference, but there is nothing wrong with assigning a value to it with=, at least in general. It is non-const. So once it is instantiated (which is guaranteed, via the initialization list inProperty‘s only constructor), assigning a value to it does not attempt to reseat it, but instead assigns a new value to the memory location to which it refers.
I will provide the larger file prop.cpp which contains (successful) unit tests for each of Property‘s member functions, if requested.
You may notice that this code is an attempt to (partially) implement “function-like” (“C#-style”) properties in C++. But this question is not about whether or not it would actually be appropriate to do this a real-world C++ project, nor is it about whether or not the pattern I have chosen is the most appropriate. It’s possible that I’ll ask separate questions about that later. If you want to comment on or criticize my approach, I am interested. I only ask that you not do it here, because it would distract from the more specific purpose of this question. Instead, you could post your own question, possibly with your own answer, and post a brief comment here linking to your new question.
As the compiler said, non-static reference cannot be assigned using the compiler-generated assignment operator. A user-defined copy assignment operator is required.
Your user-defined assignment operator performs assignment to the object referenced by
value, by calling first youroperator T()to obtain a temporary value of typeTand then yourProperty<T>& operator=(T a)to executevalue = a, which replaces the referenced-to object with the value obtained from the conversion operator.If nothing is derived from your class, your operator= is equivalent to