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 forcpstd::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:
}
1 Answer 1
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:
}
-
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.the busybee– the busybee2023年10月27日 09:43:25 +00:00Commented 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 systemsCheche Romo– Cheche Romo2023年10月27日 17:25:27 +00:00Commented Oct 27, 2023 at 17:25
-
2As 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.the busybee– the busybee2023年10月27日 17:48:09 +00:00Commented Oct 27, 2023 at 17:48
-
@thebusybee, you're right, im removing the questions from the answerCheche Romo– Cheche Romo2023年10月27日 17:52:57 +00:00Commented Oct 27, 2023 at 17:52
cpstd::vector<unsigned char> myVector{0, 1, 2, 3, 4};
(without the=
)?