I was halfway through working on this piece of code and thought this is obviously not going to compile before hitting the build button. I was surprised that it not only compiled, but linked and worked as well.
If I were to guess I would say that SFINAE is responsible for it compiling... is it?
struct BaseClass
{
public:
BaseClass() {}
template<typename T>
BaseClass(const T& a_other)
{
int i = 0; // for break point
}
template<typename T>
BaseClass& operator= (const T& a_other)
{
int i = 0; // for break point
return *this;
}
private:
BaseClass(const BaseClass& a_other); // Does not have a definition
BaseClass& operator= (const BaseClass& a_other); // Does not have a definition
};
struct MyClass : public BaseClass
{
};
int main()
{
MyClass i, j;
i = j;
return 0;
}
EDIT: I am using Visual-C++ 2008, maybe it is an odd quirk of VS
The code is not legal.
i = j
calls the implicitly defined copy assignment operator in MyClass
. This function calls the copy assignment operator for each of its sub-objects, including direct base classes [class.copy 12.8 p28].
If you add code to the copy assignment operator for BaseClass you can see where VS is going wrong:
template<typename T>
BaseClass& operator= (const T& a_other)
{
std::cout << typeid(T).name() << '\n';
int i = 0; // for break point
return *this;
}
For me this prints out "struct MyClass". VS is calling the BaseClass
copy assignment operator by passing the parameter received in MyClass:operator=
directly, rather than just the BaseClass
sub object of j.
SFINAE doesn't come into play because the template functions aren't failing. VS is simply generating the implicit copy assignment operator incorrectly.
To sum up: VS is generating the implicit copy assignment operator as
MyClass &operator=(const MyClass& rhs) {
static_cast<BaseClass&>(*this).operator=(rhs);
return *this;
}
When it should be:
MyClass &operator=(const MyClass& rhs) {
static_cast<BaseClass&>(*this).operator=(static_cast<const BaseClass&>(rhs));
return *this;
}
Shot in the dark: the compiler instantiates the base class’ operator =
with T
= MyClass
. I do now know whether this is legal or even required but it makes a certain kind of sense: the auto-generated code for operator =
essentially looks like this (well, pseudo-code):
MyClass& operator =(MyClass const& other) {
BaseClass::operator =(other);
return *this;
}
Now the compiler finds that BaseClass::operator =<MyClass>(MyClass const&)
is the best match and instantiates it.
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