1

I'm working with a custom C++ library, CPSTL, for Arduino, which includes a cpstd::vector class that is designed to work with cpstd::initializer_list, cpstd::initializer_list is supposed to mimic std::initializer_list.

However, I'm having trouble initializing a cpstd::vector using brace-enclosed initializer lists.

I've looked up many sources online, and it seems there is not a lot of information in the topic, but came up to things such as FastArduino: initializer list, and Arduino STL: Initializer list. Giving me hopes that it is actually possible. (I can't use those libraries, because they lack the build system generation tools on the library I am developing, they also lack on customizability, and also as a good learning experience)

I've tried various approaches, but I keep getting the error:

could not convert '{0, 1, 2, 3, 4}' from 'brace-enclosed initializer list' to 'cpstd::vector'.

Here's an example of the code that's causing the issue:

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

I have already implemented a custom cpstd::initializer_list and constructor that should handle this, but the issue persists. Is there something specific to the Arduino environment that could be causing this issue?

Additional Information:

  • I have verified that the cpstd::initializer_list is correctly defined and included in my code.

  • The cpstd::vector class is included and accessible.

  • I have reviewed my cpstd::vector class, and the constructor for cpstd::initializer_list is correctly implemented.

  • While reading the error log, I noticed that std::initializer_list constructor has two parameters, a pointer to the data, and also a variable telling the length of the braced enclosed list, however I noticed that the list ends up casting to a single parameter, hence having no possible constructor to call

What could be causing this issue, and how can I resolve it to initialize cpstd::vector using brace-enclosed initializer lists in the Arduino environment? I think the main issue is with boards that have no STL support. (i.e. AVR based boards)

I've came to the conclusion that it will not be possible to create such constructors/operators due to compiler limitations, I think I've tried anything that came to mind. But I don't want to give up on this without knowing if there is a workaround.

edit (removed previous code snippets for clarity, added minimal code example reproducing the error) :

minimal sketch reproducing the error:

#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() {
  // put your setup code here, to run once:
  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() {
  // put your main code here, to run repeatedly:

}
5
  • 2
    To the close voters because "off-topic": Since the Arduino build system does magic under the hood, it can well be the "culprit." Therefore, I see this question as on-topic. Commented Oct 27, 2023 at 5:52
  • The underlying compiler system is a common GCC, therefore I don't think that the compiler is limited. However, my current situation does not allow me to investigate by reproducing the issue. -- In the meantime, would you mind to edit your question and extend the provided source to a minimal, complete, and reproducible example, please? You don't want each of us to invest that time,do you? Commented Oct 27, 2023 at 5:55
  • @thebusybee my bad, I'll sure add a complete, and reproducible example Commented Oct 27, 2023 at 5:57
  • Just a random thought: does it work if you initialize the vector with cpstd::vector<unsigned char> myVector{0, 1, 2, 3, 4}; (without the =)? Commented Oct 27, 2023 at 9:39
  • @EdgarBonet I did try, but the same happens, since the problem is that the compiler wont convert {x, x, x} to a cpstd::initializer_list Commented Oct 27, 2023 at 17:27

1 Answer 1

0

So I have been messing around with the minimal example code and found a working solution, I'll post the solution just in case someone finds themselves having the same issue on the future, the only downside is that it feels a bit hacky to my taste, I still wonder if there is a better solution. And would gratly appreciate any feedback.

I found out that the compiler does not ackowledges the initializer_list class for braced enclosed initializers if the class is not under the namespace std.

The way I came arround this problem lies on using the preprocessor directive below:

#if __has_include(<initializer_list>)

With this line conditional compilation takes place, and we can specify what to do whenever std::initializer_list is present or not.

  • If std::initializer_list is not present an implementation is provided.
  • cpstd::intitlizer_list is only a template alias of std::intitializer_list

minimal sketch with the solution:

#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() {
  // put your setup code here, to run once:
  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() {
  // put your main code here, to run repeatedly:

}
4
  • Well done! Unfortunately answer should not contain follow-up questions, and the one about the keyword looks as non-Arduino specific, too. I suggest to post this one separately on Stack Overflow. Commented Oct 27, 2023 at 9:43
  • I added the questions in my answer in case someone else wanted to add another answer, I think those are arduino specific questions because it implies using the arduino toolchain to reproduce the problems, I did not have this issues when compiling on other systems Commented Oct 27, 2023 at 17:25
  • 2
    As I commented, the underlying compiler is a common GCC. There is apparently nothing Arduino specific. However, this second question is a different issue, and as such needs its own question. You might want to link back to here. Please note that this is not a forum. Commented Oct 27, 2023 at 17:48
  • @thebusybee, you're right, im removing the questions from the answer Commented Oct 27, 2023 at 17:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.