#include <cstddef>
#include <cstdint>
#include <iostream>

template<size_t bytesLeft>
void doXor(void *p1, void *p2) {
	*reinterpret_cast<uint64_t*>(p1) ^= *reinterpret_cast<uint64_t*>(p2);
	doXor<bytesLeft - 8>(reinterpret_cast<uint8_t*>(p1) + 8, reinterpret_cast<uint8_t*>(p2) + 8);
}
template<>
void doXor<0>(void*, void*) {}
template<>
void doXor<1>(void *p1, void *p2) {
	*reinterpret_cast<uint8_t*>(p1) ^= *reinterpret_cast<uint8_t*>(p2);
}
template<>
void doXor<2>(void *p1, void *p2) {
	*reinterpret_cast<uint8_t*>(p1) ^= *reinterpret_cast<uint8_t*>(p2);
	*(reinterpret_cast<uint8_t*>(p1) + 1) ^= *(reinterpret_cast<uint8_t*>(p2) + 1);
}
template<>
void doXor<3>(void *p1, void *p2) {
	*reinterpret_cast<uint8_t*>(p1) ^= *reinterpret_cast<uint8_t*>(p2);
	*(reinterpret_cast<uint8_t*>(p1) + 1) ^= *(reinterpret_cast<uint8_t*>(p2) + 1);
	*(reinterpret_cast<uint8_t*>(p1) + 2) ^= *(reinterpret_cast<uint8_t*>(p2) + 2);
}
template<>
void doXor<4>(void *p1, void *p2) {
	*reinterpret_cast<uint32_t*>(p1) ^= *reinterpret_cast<uint32_t*>(p2);
}
template<>
void doXor<5>(void *p1, void *p2) {
	*reinterpret_cast<uint32_t*>(p1) ^= *reinterpret_cast<uint32_t*>(p2);
	doXor<1>(reinterpret_cast<uint8_t*>(p1) + 4, reinterpret_cast<uint8_t*>(p2) + 4);
}
template<>
void doXor<6>(void *p1, void *p2) {
	*reinterpret_cast<uint32_t*>(p1) ^= *reinterpret_cast<uint32_t*>(p2);
	doXor<2>(reinterpret_cast<uint8_t*>(p1) + 4, reinterpret_cast<uint8_t*>(p2) + 4);
}
template<>
void doXor<7>(void *p1, void *p2) {
	*reinterpret_cast<uint32_t*>(p1) ^= *reinterpret_cast<uint32_t*>(p2);
	doXor<3>(reinterpret_cast<uint8_t*>(p1) + 4, reinterpret_cast<uint8_t*>(p2) + 4);
}

template<typename T>
T& operator^=(T& a, T& b) {
	doXor<sizeof(T)>(&a, &b);
	return a;
}

struct A {
	uint64_t a;
	uint64_t b;
	uint64_t c;
	uint64_t d;
};

int main() {
	A a{1,2,3,4};
	A b{5,6,7,8};
	
	std::cout << a.a << " " << a.b << " " << a.c << " " << a.d << std::endl;
	std::cout << b.a << " " << b.b << " " << b.c << " " << b.d << std::endl;

	a ^= b;
	b ^= a;
	a ^= b;
	
	std::cout << a.a << " " << a.b << " " << a.c << " " << a.d << std::endl;
	std::cout << b.a << " " << b.b << " " << b.c << " " << b.d << std::endl;
}