10

In 8.4.2 Explicitly-defaulted functions [dcl.fct.def.default] of the standard,

Explicitly-defaulted functions and implicitly-declared functions are collectively called defaulted functions, and the implementation shall provide implicit definitions for them (12.1 12.4, 12.8), which might mean defining them as deleted. A special member function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. A user-provided explicitly-defaulted function (i.e., explicitly defaulted after its first declaration) is defined at the point where it is explicitly defaulted; if such a function is implicitly defined as deleted, the program is ill-formed. [ Note: Declaring a function as defaulted after its first declaration can provide efficient execution and concise definition while enabling a stable binary interface to an evolving code base.—end note ]

What does the note at the end mean? From what I can see, declaring a function as defaulted after its first declaration will make the function user-provided, thus make the function non-trivial, and thus either make the type having non-trivial default constructor or make the type non-trivially-copyable, and of course make the type non-trivial and non-POD, while still have the implementation to provide the function's actual definition. But I don't understand how this leads to "provide efficient execution and concise definition while enabling a stable binary interface to an evolving code base". Any thoughts are welcome and real-world examples are highly appreciated. Thanks.

An example of such type:

struct A {
    A();
};
A::A() = default;
goodbyeera
  • 3,169
  • 2
  • 18
  • 39
  • A good question, sir. – Lightness Races in Orbit Mar 28 '14 at 11:55
  • 2
    I think what is meant is that given `struct A { A(); }; A::A() { }`, changing it to `struct A { A() = default; };` is a breaking change (already-compiled code using the class needs to be recompiled), but changing it to `struct A { A(); }; A::A() = default;` is not a breaking change. –  Mar 28 '14 at 11:57
  • 1
    I agree with @hvd, who should have posted his answer as an answer, not a comment. – Lightness Races in Orbit Mar 28 '14 at 12:01
  • I posted it as a comment because I felt it was too much of a guess. :) But if it looks correct, I'll post it as an answer in a short while when I can expand a bit. –  Mar 28 '14 at 12:03

1 Answers1

7

Suppose you have

// A.h
struct A {
  A();
};

and

// A.cc
A::A() { }

You can change it to

// A.cc
A::A() = default;

to not force code using A.h to be recompiled.

For a default constructor, this doesn't make much sense. = default takes up more characters than { }. But think of other constructor types: a copy or move constructor may become much shorter if it is no longer necessary to explicitly mention each field, and depending on the compiler and type you're dealing with, the defaulted copy/move constructor may even perform better, for example if the compiler can only detect that a memcpy call will suffice when you use the = default syntax.

  • 2
    +1: I think this is it. The key is that the triviality must have been forfeited from the outset for the clause to apply. – Lightness Races in Orbit Mar 28 '14 at 12:18
  • Thank you very much for the thoughts. For the case of copy ctor, so you're saying, though the type is made as non-trivially-copyable with this "deferred =default definition" syntax, implementation can still do things like `memcpy` when it sees appropriate? This seems to be conflicting with the requirement in `3.9[basic.types] paragraphs 3`, which states only trivially copyable types guarantee byte-wise copy equivalence. – goodbyeera Mar 28 '14 at 12:21
  • @goodbyeera When the compiler knows that on that specific implementation, `memcpy` will do exactly the same thing as what the standard describes, the compiler is certainly allowed to call `memcpy`. Not just for copy constructors, but everywhere. –  Mar 28 '14 at 12:28
  • @hvd: In that sense, wouldn't the compiler perform `memcpy` optimization for plain `{}` definition too? – goodbyeera Mar 28 '14 at 12:34
  • @goodbyeera It's allowed, but it may be significantly harder for the compiler to detect that it's possible. A field-by-field assignment in the copy constructor function body may look to the compiler as if it should avoid copying any internal padding bytes. –  Mar 28 '14 at 12:36
  • Not just the compiler matters. Implementors of containers can use type traits to detect triviality and change their algorithms appropriately. Even in an optimizing compiler, you might want to maximize performance in unoptimized debug builds and hence type traits and language-detectable triviality is important. – Sean Middleditch Mar 28 '14 at 17:53
  • @SeanMiddleditch If the in-class declaration of the constructor doesn't specify it as defaulted, then that isn't possible. –  Mar 28 '14 at 17:58
  • @hvd: hence why I commented to note the value of putting it in the class definition. Should've been clear about that, sorry. – Sean Middleditch Mar 28 '14 at 21:29