RVO forçar erro de compilação na falha

Muitas discussões aqui sobre quando o RVO pode ser feito, mas não muito sobre quando realmente é feito. Como mencionado, a RVO não pode ser garantida de acordo com o Padrão, masExiste uma maneira de garantir que a otimização de RVO seja bem-sucedida ou que o código correspondente não seja compilado?

Até agora eu consegui parcialmente fazer o código emitir erros de link quando o RVO falha. Para isso eu declaro os construtores de cópia sem defini-los. Obviamente, isso não é robusto nem viável nos casos não raros em que preciso implementar um ou ambos os construtores de cópia, ou seja,x(x&&) ex(x const&).

Isso me leva à segunda pergunta:Por que os escritores do compilador escolheram ativar o RVO quando os construtores de cópia definidos pelo usuário estão em vigor, mas não quando apenas os construtores de cópia padrão estão presentes?

Terceira pergunta:Existe alguma outra maneira de ativar o RVO para estruturas de dados simples?

Última pergunta (promessa):Você conhece algum compilador que faz com que meu código de teste se comporte com outro, então observei com o gcc e o clang?

Aqui está um exemplo de código para o gcc 4.6, gcc 4.8 e clang 3.3 que mostra o problema. O comportamento não depende de configurações gerais de otimização ou depuração. É claro opção--no-elide-constructors faz o que diz, ou seja, desliga o RVO.

#include <iostream>
using namespace std;

struct x
{
    x () { cout << "original x address" << this << endl; }
};
x make_x ()
{
    return x();
}

struct y
{
    y () { cout << "original y address" << this << endl; }
    // Any of the next two constructors will enable RVO even if only
    // declared but not defined. Default constructors will not do!
    y(y const & rhs);
    y(y && rhs);
};
y make_y ()
{
    return y();
}

int main ()
{
    auto x1 = make_x();
    cout << "copy of  x address" << &x1 << endl;
    auto y1 = make_y();
    cout << "copy of  y address" << &y1 << endl;
}

Saída:

original x address0x7fff8ef01dff
copy of  x address0x7fff8ef01e2e
original y address0x7fff8ef01e2f
copy of  y address0x7fff8ef01e2f

O RVO também parece não funcionar com estruturas de dados simples:

#include <iostream>

using namespace std;

struct x
{
    int a;
};

x make_x ()
{
    x tmp;
    cout << "original x address" << &tmp << endl;
    return tmp;
}

int main ()
{
    auto x1 = make_x();
    cout << "copy of  x address" << &x1 << endl;
}

Saída:

original x address0x7fffe7bb2320
copy of  x address0x7fffe7bb2350

ATUALIZAR: Observe que algumas otimizações são muito facilmente confundidas com o RVO. Ajudantes de construtores comomake_x são um exemplo. Vejoeste exemplo onde a otimização é realmente aplicada pelo padrão.

questionAnswers(3)

yourAnswerToTheQuestion