Ответ 1
Для T = &C::m
нет operator<<(std::ostream&, T)
. Обычно вы получите сообщение об ошибке.
Но вместо этого существует один для T = bool
и неявное преобразование из указателя-члена в bool
. Таким образом, результат, который вы видите, является результатом того, что эти указатели не являются нулевыми (преобразуются в true
).
Попробуйте это, например:
#include <iomanip>
#include <iostream>
struct A
{
int x, y, z;
};
int main()
{
std::cout << std::boolalpha; // print boolean values as text
std::cout << &A::x << std::endl;
std::cout << &A::y << std::endl;
std::cout << &A::z << std::endl;
}
Вывод:
верно
правда
true
Обратите внимание, что в коде printf("%p", &A::X)
у вас есть поведение undefined.
Значение для спецификатора %p
должно быть void*
, и нет преобразования от указателя-члена к void*
. Вместо этого у вас есть псевдонимы (типа-каламбуры) до void*
, которые являются undefined. (Предположим, что sizeof(&A::x)
было 4, а sizeof(void*)
было 64, ничто не говорит, что этого не может быть.)
Вам просто нужно понять, что не все указатели можно рассматривать как целочисленные смещения. То, что мы можем даже напечатать указатель, определяется реализацией: он может печатать "яблоко" для нулевого, "груши" для одного значения и "молоко" для другого, если захотела (немой) реализация. Я затронул эту разницу между значениями и их представлениями до.
И в этом случае выход для значения вообще отсутствует. И это хорошо, не все значения имеют значимые печатные выходы. Самое большее, что вы можете сделать, это распечатать отдельные биты:
#include <climits>
#include <iostream>
#include <type_traits>
template <typename T>
auto print_bits(const T& value)
-> typename std::enable_if<std::is_standard_layout<T>::value>::type
{
// it okay to alias a standard-layout type as a sequence of bytes:
const auto valueAsBytes = reinterpret_cast<const unsigned char*>(&value);
for (std::size_t byte = 0; byte < sizeof(T); ++byte)
{
// print in reverse order
const std::size_t byteIndex = sizeof(T) - byte - 1;
const unsigned char byteValue = valueAsBytes[byteIndex];
for (std::size_t bit = 0; bit < CHAR_BIT; ++bit)
{
// print in reverse order
const std::size_t bitIndex = CHAR_BIT - bit - 1;
const bool bitValue = (byteValue & (1U << bitIndex)) != 0;
std::cout << (bitValue ? 1 : 0);
}
std::cout << ' ';
}
std::cout << std::endl;
}
(Я печатаю байты и биты в обратном порядке, потому что на моих архитектурах это помещает младший бит справа. Я предпочитаю просматривать двоичные значения таким образом.)
Это дает:
struct A
{
int x, y, z;
};
int main()
{
// example:
for (unsigned i = 0; i < 64; ++i)
print_bits(i);
std::cout << std::endl;
// member-pointers:
print_bits(&A::x);
print_bits(&A::y);
print_bits(&A::z);
}
Вывод:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010
[...]
00000000 00000000 00000000 00111101
00000000 00000000 00000000 00111110
00000000 00000000 00000000 0011111100000000 00000000 00000000 00000000
00000000 00000000 00000000 00000100
00000000 00000000 00000000 00001000
Нет никаких гарантий того, что вы видите для указателей-членов.