Reputation: 1485
I'm looking for a way to pass the template arguments of a template-based class (the main class of the FastLED library on Arduino, to be specific) via the constructor of my own class (which should basically wrap the FastLED library). I want to specify the template arguments necessary to initialize FastLED in the main function, so that all pre-configuration before compiling (i.e. the #define
s in the third code block below) works via constants in the main file. How can I achieve this?
Currently, my class looks like this:
LEDState.h:
#pragma once
#include "FastLED.h"
FASTLED_USING_NAMESPACE
class LEDState {
private:
CRGB* _leds;
CRGB* _pixels;
const uint16_t _pixel_count;
const uint16_t _led_count;
const uint8_t _mapmode;
public:
LEDState(const uint16_t pixel_count, const uint8_t mapmode);
void show();
};
LEDState.cpp:
#include "LEDState.h"
LEDState::LEDState(const uint16_t pixel_count, const uint8_t mapmode)
: _pixel_count(pixel_count), _mapmode(mapmode), _led_count(_pixel_count * (_mapmode & 0x0f))
{
_leds = (CRGB*)malloc(_led_count * sizeof(CRGB));
_pixels = (CRGB*)malloc(_pixel_count * sizeof(CRGB));
FastLED.addLeds<CHIPSET, DATA_PIN, CLOCK_PIN, COLOR_ORDER>(_leds, _led_count);
}
void LEDState::show() {
for( int p = 0; p < _pixel_count; p++ ) {
_leds[p] = _pixels[p];
}
FastLED.show();
}
My problem is that I did not find a way to pass the template arguments <CHIPSET, DATA_PIN, CLOCK_PIN, COLOR_ORDER>
via the constructor of LEDState
.
Is there a way to initialize my wrapper class and the wrapped FastLED library from my main file? I'm imagining my main.ino
file like this:
#include "LEDState.h"
#define CHIPSET APA102
#define DATA_PIN 23
#define CLOCK_PIN 18
#define COLOR_ORDER GRB
LEDState state = LEDState<CHIPSET, DATA_PIN, CLOCK_PIN, COLOR_ORDER>(led_count, map_mode);
void setup() {
}
void loop() {
LEDState.show();
}
(with APA102
and GRB
being constants from the FastLED library.)
Is something like this possible at all?
(I'm not confident that I know the right vocabulary to search for a solution, leave alone using the right terminology in this question. Everything I found either wasn't a solution to my problem or I didn't understand that it was a solution. I'm coming from "plain Arduino C"; and my knowledge about C++ templates is roughly at: I can work my way through patching existing template code, but I don't know how to create a template.)
EDIT: With the comments and first answers, I guess that I need my class to also be templated. I tried copying the template argument list from the FastLED library (see link above), resulting in this class definition:
template<ESPIChipsets CHIPSET, uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder COLOR_ORDER>
class LEDState {
...
}
(ESPIChipsets
and EOrder
are defined by FastLED)
Now the compiler complains with
LEDState.cpp:3:1: error: invalid use of template-name 'LEDState' without an argument list
LEDState::LEDState(const uint16_t pixel_count, const uint8_t mapmode)
^
What else do I need to make it compile?
Upvotes: 0
Views: 408
Reputation: 312
I suggest you look into the FastLED implementation, it is written exactly how you want to use your wrapper class. I am missing some libraries so I cannot tell if everything compiles, but the solution must be close to this
template <ESPIChipsets chipset, uint8_t data_pin, uint8_t clock_pin, EOrder rgb_order = RGB>
class LEDState {
private:
std::unique_ptr<CRGB[]> _leds;
std::unique_ptr<CRGB[]> _pixels;
const uint16_t _pixel_count = 0;
const uint16_t _led_count = 0;
const uint8_t _mapmode = 0;
public:
LEDState(const uint16_t pixel_count, const uint8_t mapmode)
: _pixel_count(pixel_count), _mapmode(mapmode), _led_count(_pixel_count* (_mapmode & 0x0f))
{
if (_pixel_count > 0)
{
_leds = std::make_unique(new CRGB[_led_count]);
_pixels = std::make_unique(new CRGB[_pixel_count]);
FastLED.addLeds<chipset, data_pin, clock_pin, rgb_order>(_leds, _led_count, RGB_ORDER);
}
}
void show() {
}
};
#define CHIPSET APA102
#define DATA_PIN 23
#define CLOCK_PIN 18
#define COLOR_ORDER GRB
int main()
{
const uint16_t pixel_count = 3;
const uint8_t map_mode = 0;
LEDState<CHIPSET, DATA_PIN, CLOCK_PIN, COLOR_ORDER> state(pixel_count, map_mode);
}
Upvotes: 1
Reputation: 234
You seem to actually want a class template. Here is how you create one in C++
#include <iostream>
template < class T >
class my_class {
public:
typedef T type;
my_class() {
std::cout << sizeof( type ) << '\n';
}
};
int main()
{
auto A = my_class< double >();
auto B = my_class< float >();
auto C = my_class< char >();
return 0;
}
Upvotes: 0
Reputation: 774
No. What you want to do is not possible.
Your question is related to this, and the same answer applies.
What you want to do would be achieved by a class template. For instance:
template<std::size_t N> class foo { /* interface*/ };
which you can then instantiate pretty similarly as you wanted:
foo<10> bar;
/* Use bar */
Upvotes: 0