#c #templates #std
Вопрос:
Мне нужно сопоставить адреса периферийной памяти для доступа к оборудованию в Linux. Чтобы сделать вещи немного более общими (они же сложные…) Я создал следующую функцию:
template<typename Tp>
static Tp* getPeripheralPtr(unsigned address)
{
static constexpr auto deleter = [](Tp* ptr){ munmap(ptr, sizeof(Tp); };
static std::unique_ptr<Tp> ptr(nullptr, deleter);
if (!ptr)
{
/* mmap logic */
ptr.reset(reinterpret_cast<Tp*>(virtaddr));
}
return ptr.get();
}
где Tp — структура, представляющая регистры.
Это сработало довольно хорошо, хотя позже в процессе я понял, что у меня может быть несколько контроллеров, например PWM0, PWM1 с одинаковым расположением регистров, только со смещением. Поэтому я переписал функцию:
template<typename Tp, size_t nControllers = 1, size_t offset = 0>
static Tp* getPeripheralPtr(unsigned address, int idx = 0)
{
static Storage<Tp, nControllers> storage;
if (!storage.ptr[idx])
{
/* mmap magic */
}
return storage.ptr[idx].get();
}
Мне нужен был способ инициализации N экземпляров std::unique_ptr, поэтому я создал вспомогательный класс хранения:
template<typename Tp, std::size_t N>
class Storage
{
static constexpr auto deleter = [](Tp* ptr) { munmap(ptr, sizeof(Tp)); };
template<size_t ... indices>
explicit Storage(std::index_sequence<indices...> constamp;)
: ptr{{((void)indices, ptr_type(nullptr, deleter))...}}
{
}
public:
using ptr_type = std::unique_ptr<Tp, decltype(deleter)>;
ptr_type ptr[N];
Storage() : Storage(std::make_index_sequence<N>{}) {}
};
Но это дает мне ошибку, когда nControllers > 1 сообщает об отсутствии соответствующего конструктора для инициализации «Хранилища><int, 2>::ptr_type». Не могли бы вы, пожалуйста, указать мне правильное направление?
Комментарии:
1. Используйте
std::array
для этого вместо C-массива.2. ух ты, это сработало.. Но мне интересно.. Почему это так? Что изменилось в использовании std::array? Если вы сформулируете это в реальном ответе, я приму и поддержу 🙂
3. При инициализации необработанного массива у вас есть лишняя пара фигурных скобок. Если, конечно, мои глаза не слишком устали.
4. @Рассказчик-UnslanderMonica, черт возьми. Наверное, я слишком устал для этого. Но это заставляет меня задуматься… Почему это сработало с std::массивом с дополнительными фигурными скобками… Что ж, большое вам спасибо за решение этой проблемы!
5. A
std::array
-это в основном структура с общедоступным необработанным элементом массива. Таким образом, внешние фигурные скобки инициализировали структуру как совокупность, а внутренние-открытый элемент.
Ответ №1:
С этим:
ptr{{((void)indices, ptr_type(nullptr, deleter))...}}
Вам нужен тип внутри initializer_list
конструктора. И очевидно, что вы не могли бы использовать только необработанный C-массив. Если вы удалите один уровень фигурных скобок, вы можете использовать его с необработанным C-массивом.