É um comportamento definido fazer referência a um membro inicial de uma expressão de membro posterior durante a inicialização agregada?

Considere o seguinte:

struct mystruct
{
    int i;
    int j;
};

int main(int argc, char* argv[])
{
    mystruct foo{45, foo.i};   

    std::cout << foo.i << ", " << foo.j << std::endl;

    return 0;
}

Observe o uso defoo.i na lista agregador-inicializador.

g++ 5.2.0 saídas

45, 45

Esse comportamento é bem definido? Éfoo.i neste inicializador agregado sempre garantido para se referir à estrutura que está sendo criadai elemento (e&foo.i se referiria a esse endereço de memória, por exemplo)?

Se eu adicionar um construtor explícito aomystruct:

mystruct(int i, int j) : i(i), j(j) { }

Então, recebo os seguintes avisos:

main.cpp:15:20: warning: 'foo.a::i' is used uninitialized in this function [-Wuninitialized]
     a foo{45, foo.i};
                ^
main.cpp:19:34: warning: 'foo.a::i' is used uninitialized in this function [-Wuninitialized]
     cout << foo.i << ", " << foo.j << endl;

O código é compilado e a saída é:

45, 0

Claramente, isso faz algo diferente, e estou assumindo que esse seja um comportamento indefinido. É isso? Se sim, por que a diferença entre isso e quando não havia construtor? E, como posso obter o comportamento inicial (se fosse um comportamento bem definido) com um construtor definido pelo usuário?

questionAnswers(4)

yourAnswerToTheQuestion