Bypassing an auto-generated assignment operator (VS error?)

Take the following code:

class Foo { Foo const& operator =(Foo const& rhs); // disallow }; struct Bar { public: Foo foo; template <class T> T const& operator =(T const& rhs) { return rhs; } }; struct Baz : public Bar { using Bar::operator =; }; int main() { Baz b1, b2; b1 = b2; } 

This will not compile because it will use the automatically generated assignment operator for the operator Bar :: operator =, which tries to use Foo :: operator =, which is private. Good. So I added to the extra member in Bar:

 Bar const& operator =(Bar const& b) { return Bar::operator=<Bar>(b); } 

Now we have another problem. I have two overloads, only one of which can be used. I am going to Baz const &. All that I know about C ++ suggests that this should end with a version without templates, because matching non-templates are selected first. It also looks like what gcc does. Visual Studio doesn't seem to agree:

 error C2666: 'Bar::operator =' : 2 overloads have similar conversions could be 'const Bar &Bar::operator =(const Bar &)' or 'const T &Bar::operator =<Baz>(const T &)' with [ T=Baz ] while trying to match the argument list '(Baz, Baz)' 

I am tempted to believe in gcc here because my understanding of C ++ confirms this, and because I am generally a supporter of gcc when it does not agree with Visual Studio, but I am not really so concerned about this, as I am talking about it

In my non-minimal example, I honestly don’t need this default assignment operator at all. I would be more than happy if the template operator does the job - it does it right. However, since VS complains about a conflict between the template and the automatically generated assignment operator, I cannot get this template to work at all. I tried all of the following:

  • Make the assignment operator private and unrealized (does not work because "not all overloads are valid")
  • Creating it (which leads to the error above)
  • Leaving it (leading to the error above with the default assignment operator)
  • Creating a template specialization for this type, thus matching the default assignment operator exactly (is clearly illegal according to the compiler)

Does anyone have any bright ideas on how I can get around this problem? Unfortunately, my VS version does not support overriding the C ++ 0x β€œdelete” auto-generated assignment operator, so this is not an option, and I cannot think of other ways to get around this error.

+4
source share
1 answer

The ambiguity that occurs when resolving between two versions of an assignment operator is caused by "using Bar :: operator =" in the Baz definition.

Implicit or explicitly defined in Bar, a version without a template accepts the argument "const Bar &", which does not exactly match "Baz", as required for unambiguous resolution compared to the template.

There are many ways around this, but the real solution will depend on the real source.

To fix the example, I would do the following things:

o Prevent auto-generation const Bar& operator =(const Bar& b) , because it will use the assignment operator Foo. What you have tried to add to the definition of Bar will work:

 Bar const& operator =(Bar const& b) { return Bar::operator=<Bar>(b); } 

o using Bar::operator = in the definition Base needs to go. Replace it with the function that wraps Bar :: operator =. For instance:

 template <class T> const T& operator =(const T& rhs) { return Bar::operator =(rhs); } 

(Of course, non-funky code would always return * this is Bar &, not the type of the argument.)

+2
source

All Articles