С учетом следующего кода:
struct Tag {};
struct X {
// Tag t; // if not commented it shouldn't be pointer-interconvertible
int k;
};
int fn(const X& x, int& p) {
int i = x.k;
p = 2;
return i + x.k;
}
Сгенерированный код:
fn(X const&, int&):
mov eax, DWORD PTR [rdi]
mov DWORD PTR [rsi], 2
add eax, DWORD PTR [rdi]
ret
Здесь компилятор предполагает псевдоним.
Если элемент t
не является В настоящее время типы X
и int
являются взаимозаменяемыми по указателю. Таким образом, компилятор должен генерировать код, как будто ссылки могут быть псевдонимами.
Но если присутствует элемент t
, они больше не должны быть взаимозаменяемыми по указателю, и должен быть сгенерирован код для не псевдонима. Но в обоих случаях код идентичен, за исключением относительного адреса члена k
.
Ассемблер:
fn(X const&, int&):
mov eax, DWORD PTR [rdi+4]
mov DWORD PTR [rsi], 2
add eax, DWORD PTR [rdi+4]
ret
В качестве контрпример
template<typename T>
struct X {int k; };
int fn(X<struct A>& x, X<struct B>& p) {
int i = x.k;
p.k = 2;
return i + x.k;
}
в вышеприведенной версии сгенерированный код не предполагает псевдонимов, но типы являются взаимозаменяемыми по указателю.
fn(X<A>&, X<B>&):
mov eax, DWORD PTR [rdi]
mov DWORD PTR [rsi], 2
add eax, eax
ret
Может кто-нибудь объяснить это?