Copy/move elision requires explicit definition of copy/move constructors : <p>Consider the following program:</p>

<pre><code>#include &lt;iostream&gt;
#include &lt;utility&gt;

class T {
public:
    T() { printf("address at construction:    %zx\n", (uintptr_t)this); }
    // T(const T&amp;) { printf("copy-constructed\n"); } // helps
    // T(T&amp;&amp;) { printf("move-constructed\n"); }      // helps
    // T(const T&amp;) = default;                        // does not help
    // T(T&amp;&amp;) = default;                             // does not help
};

T f() { return T(); }

int main() {
    T x = f();
    printf("address after construction: %zx\n", (uintptr_t)&amp;x);
    return 0;
}
</code></pre>

<p>Compiling with <code>g++ -std=c++17 test.cpp</code> gives the following output (same with <code>clang++</code>):</p>

<pre><code>address at construction:    7ffcc7626857
address after construction: 7ffcc7626887
</code></pre>

<p>Based on the <a href="http://en.cppreference.com/w/cpp/language/copy_elision" rel="noreferrer">C++ reference</a> I would expect the program to output two equal addresses because the copy/move should be guaranteed to be elided (at least in C++17).</p>

<p>If I explicitly define either the copy or the move constructor or both (see commented out lines in the example), the program gives the expected output (even with C++11):</p>

<pre><code>address at construction:    7ffff4be4547
address after construction: 7ffff4be4547
</code></pre>

<p>Simply setting the copy/move constructors to <code>default</code> does not help.</p>

<p>The reference explicitly states</p>

<blockquote>
  <p>[The copy/move constructors] need not be present or accessible</p>
</blockquote>

<p>So what am I missing here?</p>
