Проверка расположения памяти указателя во время компиляции: сбой объединения в constexpr

Рассмотрим следующий код:

// Preamble
#include <limits>
#include <iostream>
#include <type_traits>

// Gives an unsigned int of the given size in bytes, if it exists
template <std::size_t N>
struct uint_of_sizeof
{
    using type = std::conditional_t<
        N == sizeof(unsigned char),
        unsigned char,
        std::conditional_t<
            N == sizeof(unsigned short int),
            unsigned short int,
            std::conditional_t<
                N == sizeof(unsigned int),
                unsigned int,
                std::conditional_t<
                    N == sizeof(unsigned long long int),
                    unsigned long long int,
                    std::conditional_t<
                        N == sizeof(std::size_t),
                        std::size_t,
                        std::conditional_t<
                            N == sizeof(unsigned long int),
                            unsigned long int,
                            void
                        >
                    >
                >
            >
        >
    >;
};

// Allows to reinterpret pointer as an unsigned integral value
template <class T>
union pointer_converter
{
    using pointer_type = T*;
    using value_type = typename uint_of_sizeof<sizeof(pointer_type)>::type;
    pointer_type pointer;
    value_type value;
}; 

// Returns whether the pointer seems to have a normal layout
template <class T>
constexpr bool check_pointer_layout()
{
    // Initialization
    constexpr std::size_t alignment = alignof(T);
    pointer_converter<T> converter0{nullptr};
    pointer_converter<T> converter1{nullptr};
    std::ptrdiff_t difference = 0;
    bool ok = true;

    // Checks zero and first increment
    converter1.value = alignment;
    difference = converter1.pointer - converter0.pointer;
    ok = converter0.value == 0 && difference == 1;

    // Checks shifts
    while (ok && converter1.value < converter1.value << 1) {
        ok = converter1.pointer - converter0.pointer == difference;
        converter1.value <<= 1;
        difference <<= 1;
    }

    // Finalization
    return ok;
}

// Main function
int main(int argc, char* argv[])
{
    /*constexpr*/ bool is_classical_layout = check_pointer_layout<int>(); /* HERE */
    std::cout << is_classical_layout << std::endl;
    return 0;
}

Этот код пытается проверить (очень наивно, я знаю), закодированы ли указатели в памяти, как можно предположить, и могут ли они быть более или менее безопасно переосмыслены как целые числа. Однако проблема в том, что constexpr в этом контексте не работает.

pointer_layout.cpp: 77: 68: ошибка: доступ к элементу pointer_converter:: pointer вместо инициализированного члена pointer_converter:: value в константном выражении constexpr bool is_classical_layout = check_pointer_layout();

Вопрос 1: Есть ли способ сделать это (или что-то подобное) во время компиляции?

Вопрос 2: для этого лучше использовать во время выполнения unions или же reinterpret_castили оба эквивалентны?

0 ответов

Другие вопросы по тегам