Устаревание std :: allocator <void> - PullRequest
0 голосов
/ 09 мая 2018

Связано: Почему стандартные контейнеры требуют в качестве типа элемента allocator_type :: value_type?

Говорят, что после C ++ 17 устарело следующее:

template<>
struct allocator<void>;

Интересно, устарел ли он, потому что один основной шаблон теперь может вместить allocator<void>, или вариант использования allocator<void> устарел.

Если последнее, мне интересно, почему. Я думаю, что allocator<void> полезен при указании распределителя, не привязанного к определенному типу (поэтому просто некоторые схемы / метаданные).

Ответы [ 2 ]

0 голосов
/ 08 января 2019

Дело не в том, что std::allocator<void> устарело, просто это не явная специализация.

На что это было похоже, было что-то вроде:

template<class T>
struct allocator {
    typedef T value_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    // These would be an error if T is void, as you can't have a void reference
    typedef T& reference;
    typedef const T& const_reference;

    template<class U>
    struct rebind {
        typedef allocator<U> other;
    }

    // Along with other stuff, like size_type, difference_type, allocate, deallocate, etc.
}

template<>
struct allocator<void> {
    typedef void value_type;
    typedef void* pointer;
    typedef const void* const_pointer;

    template<class U>
    struct rebind {
        typdef allocator<U> other;
    }
    // That's it. Nothing else.
    // No error for having a void&, since there is no void&.
}

Теперь, поскольку std::allocator<T>::reference и std::allocator<T>::const_reference устарели, нет необходимости в явной специализации для void. Вы можете просто использовать std::allocator<void> вместе с std::allocator_traits<std::allocator<void>>::template rebind<U>, чтобы получить std::allocator<U>, вы просто не можете создать экземпляр std::allocator<void>::allocates.

Например:

template<class Alloc = std::allocator<void>>
class my_class;  // allowed

int main() {
    using void_allocator = std::allocator<void>;
    using void_allocator_traits = std::allocator_traits<void_allocator>;
    using char_allocator = void_allocator_traits::template rebind_alloc<char>;
    static_assert(std::is_same<char_allocator, std::allocator<char>>::value, "Always works");

    // This is allowed
    void_allocator alloc;

    // These are not. Taking the address of the function or calling it
    // implicitly instantiates it, which means that sizeof(void) has
    // to be evaluated, which is undefined.
    void* (void_allocator::* allocate_mfun)(std::size_t) = &void_allocator::allocate;
    void_allocator_traits::allocate(alloc, 1);  // calls:
    alloc.allocate(1);
}
0 голосов
/ 09 мая 2018

Согласно p0174r0

Аналогично, std::allocator<void> определяется так, чтобы различные шаблоны уловки повторного связывания могут работать в исходной библиотеке C ++ 98, но это не фактический распределитель, так как ему не хватает allocate и deallocate функции-члены, которые не могут быть синтезированы по умолчанию из allocator_traits. Эта потребность ушла с C ++ 11 и void_pointer и const_void_pointer псевдонимы типа в allocator_traits. Однако мы продолжайте указывать его, чтобы избежать взлома старого кода, который имеет еще не обновлен для поддержки универсальных распределителей, для C ++ 11.

...