2

In §12 of the standard every special member function has a set of rules which cause it to be implicitly declared as defaulted and another set of rules which cause a defaulted [special member function to be] defined as deleted.

This makes it seem (to me) that there are 3 potential states when no user-declared version is present for special member functions: declared and defined (defaulted), declared and undefined (deleted), and undeclared. Is this accurate? If so, what point is there as opposed to cutting out the 'undeclared' option?

* declared as defaulted seems like a mistake, shouldn't it be "defined" as defaulted?

parapura rajkumar
  • 24,045
  • 1
  • 55
  • 85
David
  • 27,652
  • 18
  • 89
  • 138

2 Answers2

5

The difference between a deleted constructor and an implicitly undeclared constructor is that the deleted constructor participates in overload resolution, whereas the constructor that doesn't exist, doesn't participate in overload resolution.

Example:

This class is default constructible. The compiler does not implicitly declare a defaulted constructor for it.

struct A
{
    template <class ...T>
    A(T...) {}
};

int main()
{
    A a;  // ok
}

If the compiler did declare a default constructor for it, and if that default constructor was defined as deleted, then A would not be default constructible. That can be simulated with:

struct A
{
    A() = delete;  // pretend the compiler implicitly declared and defined this

    template <class ...T>
    A(T...) {}
};

int main()
{
    A a;
}

error: call to deleted constructor of 'A'
    A a;
      ^

Similar problems appear with the move constructor. If the compiler decides to implicitly declare it and define it as deleted, then one can not construct such a class from an rvalue, even if it has a viable copy constructor:

#include <type_traits>

struct A
{
    A();
    A(const A&);
    A(A&&) = delete;  // pretend compiler declared and defined
};

int main()
{
    A a = std::declval<A>();
}

error: call to deleted constructor of 'A'
    A a = std::declval<A>();
      ^   ~~~~~~~~~~~~~~~~~

But if the compiler does not implicitly declare a deleted move constructor, then things just work:

#include <type_traits>

struct A
{
    A();
    A(const A&);
};

int main()
{
    A a = std::declval<A>();  // ok
}

Indeed, if the compiler did implicitly declare a deleted move constructor for A, there would be a awful lot of broken C++98/03 code when recompiled in C++11! :-)

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
0

I not sure I agree with your summary:

There are basically three states: User Defined, Deleted or Compiler Generated

  • declared and defined
    • This means the user has explicitly declared them in the class and provided definitions.
  • declared and deleted
    • This means the user has explicitly declared them as deleted (ie they are not available).
  • undeclared
    • The user has not provided a declaration (and thus can not provide a definition).
      In this case the the compiler will generate a version of the method.
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • And the old way of doing `declared and deleted`: `declared but not defined` - the user has explicitly declared them in the class and but hasn't provided definitions. – dalle Dec 25 '11 at 09:32
  • @dalle: That's not really a part of the language; that is just a linker error waiting to happen. But yes `declared private and not defined` is the C++03 equivalent of `declared and deleted` from C++11. The C++11 way is neater as you don't need to add an extra comment saying that it is deliberately not defined (please do not add a definition). And since it is part of the language can get flagged as an error much quicker. – Martin York Dec 25 '11 at 09:42
  • @LokiAstari The 3 states I was questioning are "potential states when no user-declared version is present", they all fall under your last state. – David Dec 25 '11 at 15:21