Implementation supplied copy constructor and assignment operator

∥☆過路亽.° 提交于 2019-12-06 08:42:55

Regarding the copy constructor, this is what the standard says (12.8/7) :

A program is illformed if the class for which a copy constructor is implicitly defined has:

  • a nonstatic data member of class type (or array thereof) with an inaccessible or ambiguous copy constructor, or
  • a base class with an inaccessible or ambiguous copy constructor.

Regarding the copy assignment operator (12.8/12) :

A program is illformed if the class for which a copy assignment operator is implicitly defined has:

  • a nonstatic data member of const type, or
  • a nonstatic data member of reference type, or
  • a nonstatic data member of class type (or array thereof) with an inaccessible copy assignment operator, or
  • a base class with an inaccessible copy assignment operator.

How the compiler reports the error, or how it actually falls into it, is pretty much irrelevant from my point of view.

However, I do believe that answer (b) is probably more correct : the base class copy assignment is declared, and it's inaccessible. The derived class has an implicitly declared copy assignment which the compiler will try to define if used, thus making the program ill-formed.

A class will have a copy constructor and a copy assignment operator implicitly declared if there is no user declared version of either. This always happens.

Simplistically, the implementation will implicitly define these only if they are actually used. If, when the implementation tries to define them, the implicit definition would be ill-formed (e.g. for copy-assignment the class contains a reference member or const member or for the copy constructor a base or member has private copy constructor) then the program is ill-formed.

A program can still be valid if it contains classes which have implicitly declared copy constructors and copy assignment operators which cannot be implicitly defined so long as it does not cause these to actually be defined by using them or causing them to be used.

Your case (b) is more accurate.

C++03 Standard 12.8p10

If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly.

And 12.8p12

An implicitly-declared copy assignment operator is implicitly defined when an object of its class type is assigned a value of its class type or a value of a class type derived from its class type. A program is ill-formed if the class for which a copy assignment operator is implicitly defined has:

  • a nonstatic data member of const type, or
  • a nonstatic data member of reference type, or
  • a nonstatic data member of class type (or array thereof) with inaccessible copy assignment operator, or
  • a base class with an inaccessible copy assignment operator.

The corresponding requirements for implicitly defined copy constructors, default constructors, and destructors have similar wordings.

Specifying that the methods exist even though their definitions will be illegal clarifies some things about overload resolution. For example,

class A {
private:
  A& operator=(const A&);
};

class B : public A {
public:
  operator int() const;
  B& operator=(int);
};

void f(B& b1, const B& b2)
{ b1 = b2; }

is illegal because the implicitly-declared B::operator=(const B&) is the better overload but the implicit definition is ill-formed. Without that declaration, you might think the compiler should implicitly convert b2 to int and then assign that to b1.

I think the distinction between the two depends on the details of your specific implementation (and doesn't make much difference). For what it's worth, Comeau gives this:

"ComeauTest.c", line 7: error: "A &A::operator=(const A &)" (declared at line 4) is
          inaccessible
  struct B : A
             ^
          detected during implicit generation of "B &B::operator=(const B &)"
                    at line 16

1 error detected in the compilation of "ComeauTest.c".

So on that compiler, it detects the error "during" the implicit generation of B's assignment operator. In other words, it tries to generate it, and finds that it can't. Whether it detects it as it's writing it out, or by looking at A directly, doesn't really matter.

This is what happens :

struct A
{
private:
  A& operator = ( const A& );
};

struct B : A
{
  B& operator = ( const B& other )
  {
    A::operator=( other );
    return *this;
  }
};


int main()
{
  B b1;
  B b2;
  b1 = b2;

  return 0;
}

The default operator= tries to call A::operator=, which is private.

The standard seems to agree with you. Quoting from the current draft:

§12.8/8:

If the class definition does not explicitly declare a copy constructor and there is no user-declared move constructor, a copy constructor is implicitly declared as defaulted (8.4).

§12.8/12:

A defaulted copy/move constructor for a class X is defined as deleted (8.4.3) if X has: […]

  • a direct or virtual base class B that cannot be copied/moved because overload resolution (13.3), as applied to B’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor […]

So the synthesized copy constructor is declared and defined, but defined as deleted.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!