Принудительный статический метод в классе на основе интерфейса в C

#c #inheritance #polymorphism #static-methods #virtual-functions

#c #наследование #полиморфизм #статические методы #виртуальные функции

Вопрос:

Я создаю векторный класс, который имеет возможность принимать распределитель в качестве параметра шаблона. Чтобы гарантировать, что определяемый пользователем распределитель работает с вектором, я предоставляю интерфейс, который устанавливает минимальные требования для данного распределителя. Поскольку распределитель используется только для выделения и освобождения, у него нет переменных-членов, и все методы являются статическими. Есть ли способ убедиться, что любая реализация имеет заданный набор методов, которые также являются статическими? Я знаю, что у вас не может быть метода, который был бы статическим и виртуальным одновременно, но я по сути хочу, чтобы любой распределитель, производный от base_allocator, имел набор методов, и чтобы эти методы были статическими. Короче говоря: можете ли вы обойти virtual static противоречие в c ?

Это мой текущий код:

 // in namespace mem_core
// Interface for usage of custom allocators with the custom:: namespace containers.
template <typename T>
class base_allocator {
public:
    using T_ptr = T*;
    using T_ref = Tamp;;

    virtual T_ptr address(const T_ref value);

    // memory methods should allocate for amount elements of type T
    virtual void deallocate(T_ptr const ptr, const size_tamp; count) = 0;
    virtual T_ptr allocate(const size_tamp; amount) = 0;
};

_MEMORY_CORE_END_ // namespace mem_core }

#undef _MEMORY_CORE_BEGIN_
#undef _MEMORY_CORE_END_

// default allocator CLASS TEMPLATE
template <typename T>
class allocator : public mem_core::base_allocator<T> {
public:

    using value_type = T;
    using T_ptr = T*;
    using T_ref = Tamp;;

    static T_ptr address(T_ref value) noexcept {
        return mem_core::addressof<T>(value);
    }

    static void deallocate(T_ptr const ptr, const size_tamp; count) {
        mem_core::deallocate<T>(ptr, count);
    }

    static T_ptr allocate(const size_tamp; amount) {
        return mem_core::allocate<T>(amount);
    }
};
  

Это, конечно, работает, но нет никакой гарантии, что определяемый пользователем распределитель сделал виртуальные методы статическими, поскольку это является требованием для распределителя для работы в векторном классе.
например, так:

 template <typename T, typename alloc_type = allocator<T>>
class vector {
public:

    using iterator = vector_iterator<vector<T, alloc_type>>;

    using T_ptr = T*;
    using T_ref = Tamp;;

    using value_type = T;
private:
    T_ptr m_data;
    size_t m_size;
    size_t m_capacity;
public:
    vector() : m_data(nullptr), m_size(0), m_capacity(0) noexcept {};

    vector(const size_tamp; initial_cap) : m_size(0) {
        m_data = alloc_type::allocate(m_capacity); // Requires static allocate method
        m_capacity = initial_cap;
    }
// rest of vector class ...
  

Комментарии:

1. » Короче говоря: можете ли вы обойти виртуальное статическое противоречие в c ? » Нет. Но вы можете использовать статический полиморфизм (т.Е. Шаблоны).

Ответ №1:

Можно потребовать класс с определенными методами, определенными как статические, используя SFINAE. Следующий пример использует концепции C 20, но с небольшой доработкой может быть адаптирован для использования чистых SFINAE, поскольку это единственное, что здесь требуется. В этом примере определяется концепция has_static_methods , которая требует, чтобы класс реализовывал как «function», так и «function2» в качестве статических методов. Нестатические методы, виртуальные или нет, терпят неудачу:

 #include <iostream>
#include <type_traits>

template<typename T> struct is_function : public std::false_type {};

template<typename Ret, typename ...Args>
struct is_function<Ret (*)(Args...)> : public std::true_type {};

struct not_static {

    void function();
    static void function2();
};

struct is_static {
    static void function();
    static void function2();
};

template<typename T>
concept has_static_methods = is_function<decltype(amp;T::function)>::value amp;amp;
    is_function<decltype(amp;T::function2)>::value;

// Ok's template parameter type must implement both static methods.

template<has_static_methods T> void ok()
{
}

int main()
{
    ok<is_static>();        // OK
    ok<not_static>();       // Error, unsatisfied contsraint.
    return 0;
}
  

И с небольшой дополнительной работой можно применять статические методы с определенными сигнатурами.

Теперь имейте в виду, что это на самом деле не мешает никому определять подкласс с нестатическими методами. Для этого требуется, чтобы любой класс, который передается в качестве параметра вашему шаблону, соответствовал этому ограничению.

Комментарии:

1. Спасибо! Кажется, это помогает. Я забыл упомянуть, что я пытаюсь оставаться свободным от зависимостей, включая STL, но я думаю, что это так же просто, как реализовать необходимые функции из <type_traits>, чтобы все заработало. Еще раз спасибо!