Libraries that duplicate C++ STL

Suppose that I want to create a library that needs a particular STL function (C++ include file.)

Some boards have relatively complete C++ support, and the .../include/c++ directory, so ... no problem!

But AVR doesn't have these included by default.
Some of them are compatible with the AVR C++ compiler anyway (purer templates with no libc++ or dynamic allocation requirements), so in theory I could just copy the necessary include file into my library...

If I do that, I now have a conflict on the other platforms - which file will they pick up? Standard C++ (if it exists), or the library's copy (which might not match the compiler version)? Is there a way to force the order of the include search path?

(The feature in question is "initializer_list", if that makes any difference.)

You can take a look at GitHub - BojanJurca/Lightweight-Standard-Template-Library-STL-for-Arduino: Lightweight C++ Standard Template Library (STL) for Arduino if it suits you.

Initializer list may be a problem for AVR boards though. Arduino uses C++11 for AVR boards ...

With some help from Microsoft Copilot - there may be a workaround for AVR boards, which is converting initializer list into array first and then ustig the array in the class template constructor. Like:

template<typename T, size_t N>
class myVector {
public:
    T data [N];

    myVector (const T (&arr) [N]) {
        for (size_t i = 0; i < N; ++i) {
            data [i] = arr [i];
        }
    }

    void print () const {
        for (size_t i = 0; i < N; ++ i) {
            Serial.println (data [i]);
        }
    }
};


// Helper function to create aray from an initializer list
template<typename T, size_t N>
myVector<T, N> A (const T (&arr) [N]) {
    return myVector<T, N> (arr);
}


void setup() {

    myVector<int, 3> v ( A ( {1, 2, 3} ) );
    v.print ();

    myVector<int, 3> u = A ( {4, 5, 6} );
    u.print ();

}

void loop() {
    
}

Hi @westfw.

Are you asking which one they will use when your library is being compiled? Or are you asking which one they will use when compiling sketches that don't use your library?

The way the Arduino discovery system works is to tentatively run the preprocessor on the sketch. If preprocessing fails due to a "No such file or directory" error for an #include directive, then the libraries folders are searched for a library that provides that header file.

So in a case where the path of the STL header from the platform's toolchain is already present in the platform's predefined compiler "search paths", library discovery will not be performed for that header file and thus that #include directive in the sketch program would not cause the discovery of your library. So your library will not be used when compiling a sketch program for a board of such a platform, unless the program also contained an #include directive for another header file which triggered the discovery of your library.

Reference:

https://arduino.github.io/arduino-cli/latest/sketch-build-process/#dependency-resolution

For the predefined search paths, it would only be possible by either editing the configuration files of the boards platform or compiling the sketch by using Arduino CLI directly (because Arduino CLI allows you to define platform properties via the --build-property command line flag).

But for the paths of discovered libraries, the order of the -I flags for the library paths that are added to the compilation commands is determined by the order of the #include directives in the sketch program source code. So you can manipulate the order of those specific flags relative to each other by changing the positions of the #include directives in the sketch source code.

It claims to be in C++0x, which includes C++11.
A manual paste of the include file into a sketch seems to work...

static void set_pin(uint8_t pin)
{
  Serial.println(pin, HEX);
}

static void set_many_pins(std::initializer_list<uint8_t> pinList)
{
  uint8_t bits = 0;
  for (uint8_t pin : pinList)
  {
    bits |= 1 << pin;
  }
  set_pin(bits);
}

void setup() {
  Serial.begin(115200);
  while (!Serial) ;
  set_many_pins({ 1, 7, 5, 2 });
}

Which board are you compiling for?

The intent to to have a library that compiles on any board.
On AVR boards (with the least C++ support), it should include a private copy (in the library) of initializer_list, but on a 32bit board, it should include the STL version that is part of the compiler (.../tools/.../include/c++/initializer_list)

I guess this should do:

template <typename T, int N>
void set_many_pins (const T (&array) [N]) {
    Serial.print ("set_many_pins caled with "); Serial.print (N); Serial.println (" elements:");
    for (int i = 0; i < N; i ++) {
        Serial.print ("   "); Serial.println (array [i]);
    }
}

void setup () {
  Serial.begin (9600);
  while (!Serial);

  set_many_pins ( { 15, 17, 22 } );
}

The code above works for both AVR and 32 boards. But if there is a particular need to use initializer_list for 32 boards you can use:

#ifndef ARDUINO_ARCH_AVR
    template <typename T>
    void set_many_pins (std::initializer_list<T> pinList) {
        Serial.print ("set_many_pins caled with "); Serial.print (pinList.size ()); Serial.println (" elements:");
        for (auto pin : pinList) {
            Serial.print ("   "); Serial.println (pin);
        }
    }
#else
    template <typename T, int N>
    void set_many_pins (const T (&array) [N]) {
        Serial.print ("set_many_pins caled with "); Serial.print (N); Serial.println (" elements:");
        for (int i = 0; i < N; i ++) {
            Serial.print ("   "); Serial.println (array [i]);
        }
    }
#endif