orithena
orithena

Reputation: 1485

How to pass template arguments via constructor?

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 #defines 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

Answers (3)

stefan.gal
stefan.gal

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

Elias
Elias

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

jvd
jvd

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

Related Questions