Как обрабатывать инициализацию класса при использовании списков инициализаторов, заключенных в фигурные скобки

Я работаю с специальной библиотекой C++ CPSTL для Arduino, которая включает класс cpstd::vector, предназначенный для работы с cpstd::initializer_list , cpstd::initializer_list должен имитировать std::initializer_list.

Однако у меня возникли проблемы с инициализацией cpstd::vector с использованием списков инициализаторов, заключенных в фигурные скобки.

Я просмотрел множество источников в Интернете, и, похоже, информации по этой теме не так уж и много, но наткнулся на такие вещи, как FastArduino: список инициализаторов и Arduino STL: Список инициализаторов. Вселяя в меня надежду, что это действительно возможно. (Я не могу использовать эти библиотеки, потому что в них отсутствуют инструменты создания системы сборки в библиотеке, которую я разрабатываю, им также не хватает настраиваемости, а также хорошего опыта обучения)

Я пробовал разные подходы, но постоянно получаю ошибку:

не удалось преобразовать «{0, 1, 2, 3, 4}» из «списка инициализаторов, заключенного в фигурные скобки» в «cpstd::vector».

Вот пример кода, вызывающего проблему:

    cpstd::vector<unsigned char> myVector = {0, 1, 2, 3, 4};

Я уже реализовал собственный cpstd::initializer_list и конструктор, который должен справиться с этим, но проблема не устранена. Есть ли что-то особенное в среде Arduino, что может вызвать эту проблему?

Дополнительная информация:

  • Я проверил, что cpstd::initializer_list правильно определен и включен в мой код.

  • Класс cpstd::vector включен и доступен.

  • Я проверил свой класс cpstd::vector, и конструктор для cpstd::initializer_list реализован правильно.

  • Читая журнал ошибок, я заметил, что конструктор std::initializer_list имеет два параметра: указатель на данные, а также переменную, указывающую длину заключенного в фигурные скобки списка, однако я заметил, что список приводит к одному параметру, поэтому у него нет возможности вызвать конструктор

Что может быть причиной этой проблемы и как ее решить, чтобы инициализировать cpstd::vector с использованием списков инициализаторов, заключенных в фигурные скобки, в среде Arduino? Я думаю, что основная проблема связана с платами, у которых нет поддержки STL. (т.е. платы на базе AVR)

Я пришел к выводу, что создать такие конструкторы/операторы не удастся из-за ограничений компилятора, думаю, я попробовал все, что пришло в голову. Но я не хочу отказываться от этого, не зная, есть ли обходной путь.

изменить (для ясности удалены предыдущие фрагменты кода, добавлен минимальный пример кода, воспроизводящий ошибку):

минимальный эскиз, воспроизводящий ошибку:

#include <Arduino.h> 
#include <stddef.h> 

namespace cpstd {

  template<typename T>
  class initializer_list {
  public:
    using value_type = T;
    using reference = const T&;
    using const_reference = const T&;
    using size_type = size_t;
    using const_iterator = const T*;

  private:
    const_iterator _M_array;
    size_type _M_len;

    constexpr initializer_list(const T* array, size_type size) noexcept
      : _M_array(array), _M_len(size) {}

  public:
    constexpr initializer_list() noexcept
      : _M_array(nullptr), _M_len(0) {}

    constexpr size_type size() const noexcept {
      return _M_len;
    }
    constexpr const_iterator begin() const noexcept {
      return _M_array;
    }
    constexpr const_iterator end() const noexcept {
      return _M_array + _M_len;
    }
  };
}

template<typename T>
class exampleClass{
  protected:
    T buffer[10];
    size_t len;

  public:
    exampleClass(): len(0) {}
    exampleClass(cpstd::initializer_list<T> il){
      len = il.size();
      for(size_t i = 0; i < len; i++){
        buffer[i] = *(il.begin()+i);
      }
    }

    exampleClass& operator=(cpstd::initializer_list<T> il){
      len = il.size();
      for(auto i = il.begin(); i < il.end(); i++){
        buffer[i] = *i;
      }      
    }
    

    size_t size() const {return len;}
    T data(size_t x) const {return buffer[x];}
};


void setup() {
  // поместите сюда свой код установки для однократного запуска:
  Serial.begin(115200);
  
  exampleClass<uint8_t> myObject = {0,1,2,3}; 

  Serial.println(myObject.size());
  Serial.println(myObject.data(0));
  Serial.println(myObject.data(1));
  Serial.println(myObject.data(2));
  Serial.println(myObject.data(3));


}

void loop() {
  // поместите сюда свой основной код для многократного запуска:

}

, 👍1

Обсуждение

Для близких избирателей, потому что «не по теме»: поскольку система сборки Arduino творит чудеса под капотом, она вполне может быть «виновником». Поэтому считаю этот вопрос по теме., @the busybee

Базовая система компилятора представляет собой обычную GCC, поэтому я не думаю, что компилятор ограничен. Однако моя текущая ситуация не позволяет мне провести расследование, воспроизведя проблему. -- А пока не могли бы вы [отредактировать] свой вопрос и расширить предоставленный источник до минимального, **полного и воспроизводимого** примера, пожалуйста? Вы же не хотите, чтобы каждый из нас потратил это время, не так ли?, @the busybee

@thebusybee, моя вина, я обязательно добавлю полный и воспроизводимый пример, @Cheche Romo

Просто случайная мысль: будет ли это работать, если вы инициализируете вектор с помощью cpstd::vector<unsigned char> myVector{0, 1, 2, 3, 4}; (без =)?, @Edgar Bonet

@EdgarBonet Я пробовал, но происходит то же самое, поскольку проблема в том, что компилятор не преобразует {x, x, x} в cpstd::initializer_list, @Cheche Romo


1 ответ


Лучший ответ:

0

Итак, я возился с минимальным примером кода и нашел рабочее решение. Я опубликую решение на тот случай, если у кого-то возникнет такая же проблема в будущем. Единственным недостатком является то, что оно кажется немного хакерским. на мой вкус, я все еще задаюсь вопросом, есть ли лучшее решение. Будем признательны за любые отзывы.

Я обнаружил, что компилятор не подтверждает класс Initializer_list для заключенных в скобки инициализаторов, если этот класс не находится в пространстве имен std.

Я решил эту проблему, используя приведенную ниже директиву препроцессора:

#if __has_include(<initializer_list>)

С помощью этой строки происходит условная компиляция, и мы можем указать, что делать, когда std::initializer_list присутствует или нет.

  • Если std::initializer_list отсутствует, предоставляется реализация.
  • cpstd::intitlizer_list — это всего лишь псевдоним шаблона std::intitializer_list

минимальный набросок с решением:

#include <Arduino.h> 
#include <stddef.h> 

namespace std {

  template<typename T>
  class initializer_list {
  public:
    using value_type = T;
    using reference = const T&;
    using const_reference = const T&;
    using size_type = size_t;
    using const_iterator = const T*;

  private:
    const_iterator _M_array;
    size_type _M_len;

    constexpr initializer_list(const T* array, size_type size) noexcept
      : _M_array(array), _M_len(size) {}

  public:
    constexpr initializer_list() noexcept
      : _M_array(nullptr), _M_len(0) {}

    constexpr size_type size() const noexcept {
      return _M_len;
    }
    constexpr const_iterator begin() const noexcept {
      return _M_array;
    }
    constexpr const_iterator end() const noexcept {
      return _M_array + _M_len;
    }
  };
}

namespace cpstd {
  template<class T>
  using initializer_list = std::initializer_list<T>;
}

template<typename T>
class exampleClass{
  protected:
    T buffer[10];
    size_t len;

  public:
    exampleClass(): len(0) {}
    exampleClass(cpstd::initializer_list<T> il){
      len = il.size();
      for(size_t i = 0; i < len; i++){
        buffer[i] = *(il.begin()+i);
      }
    }

    exampleClass& operator=(cpstd::initializer_list<T> il){
      len = il.size();
      for(auto i = il.begin(); i < il.end(); i++){
        buffer[i] = *i;
      }      
    }

    size_t size() const {return len;}
    T data(size_t x) const {return buffer[x];}
};


void setup() {
  // поместите сюда свой код установки для однократного запуска:
  Serial.begin(115200);

  exampleClass<uint8_t> myObject = {0,1,2,3}; 

  Serial.println(myObject.size());
  Serial.println(myObject.data(0));
  Serial.println(myObject.data(1));
  Serial.println(myObject.data(2));
  Serial.println(myObject.data(3));


}

void loop() {
  // поместите сюда свой основной код для многократного запуска:

}
,

Отличная работа! К сожалению, ответ не должен содержать дополнительных вопросов, и вопрос о ключевом слове также выглядит неспецифичным для Arduino. Предлагаю разместить это отдельно на [so]., @the busybee

Я добавил вопросы в свой ответ на случай, если кто-то захочет добавить еще один ответ. Я думаю, что это вопросы, специфичные для Arduino, потому что это подразумевает использование цепочки инструментов Arduino для воспроизведения проблем. У меня не было таких проблем при компиляции в других системах., @Cheche Romo

Как я уже говорил, базовый компилятор представляет собой обычный GCC. Судя по всему, нет ничего особенного для Arduino. Однако второй вопрос представляет собой другую проблему и, как таковой, требует своего собственного вопроса. Возможно, вы захотите дать ссылку сюда. Обратите внимание, что это не форум., @the busybee

@thebusybee, ты прав, я убираю вопросы из ответа, @Cheche Romo