Salahuddin
Salahuddin

Reputation: 1719

How to passing one or more (undefined number) parameters to a function?

I'm writing a wrapper class for wiringPi. I would like to be able to manipulate more than one LED, by calling the function once, by passing one or more parameters to the function. The number of passed parameters should not be limited, i.e., it can be 1, 2, 3, or more. Here is my current function:

typedef enum{LED1 = 12, LED2 = 13, LED3 = 14, LED4 = 15}LED;

void Led::on(LED led)
{
    digitalWrite(led, HIGH);
}

Can I do this? and how?

I think I can use overloading for this but what if the number of parameters is undefined (i.e., it can be 1 or 7)?

Upvotes: 4

Views: 277

Answers (5)

max66
max66

Reputation: 66200

A bitfield?

If you have a little number of leds and you define their values using different bits

typedef enum {LED1 = 1, LED2 = 2, LED3 = 4, LED4 = 8};

or better (to be sure tu use only power of two values), as suggested by user2079303 (thanks!),

typedef enum {LED1 = 1 << 0, LED2 = 1 << 1, LED3 = 1 << 2, LED4 = 1 << 3};

you can pass a or-value of leds to Led::on()

on(LED1 | LED2 | LED4);

and check, inside on(), single bits

void Led::on (int leds)
 {
   if ( 0 != (leds & LED1) )
    /* do something for LED1 */;

   if ( 0 != (leds & LED2) )
    /* do something for LED2 */;

   // ...
 }

Upvotes: 4

balki
balki

Reputation: 27664

Example using variadic. This is likely the most efficient way to do this as all the work is done in compile time.

enum LED {LED1 = 12, LED2 = 13, LED3 = 14, LED4 = 15};
constexpr const int HIGH = 1;
void digitalWrite(LED, int);

template<class... LED>
void on(LED... leds)
{
    (digitalWrite(leds, HIGH), ...);
}

void foo() {
    on(LED1, LED2, LED3);
    on(LED4);
}

https://godbolt.org/g/b22y5N

Note: you need c++17 for above syntax


C++11 Compatible version:

enum LED {LED1 = 12, LED2 = 13, LED3 = 14, LED4 = 15};
constexpr const int HIGH = 1;
void digitalWrite(LED, int);

void on(LED leds)
{
    digitalWrite(leds, HIGH);
}

template<class... LEDs>
void on(LED led, LEDs... leds)
{
    on(led);
    on(leds...);
}

void foo() {
    on(LED1, LED2, LED3);
    on(LED4);
    on(LED1, LED2);
}

https://godbolt.org/g/Js13vi

Upvotes: 2

Arnav Borborah
Arnav Borborah

Reputation: 11789

You could pass a container of LEDs for this. Such as the following using std::initializer_list:

typedef enum{LED1 = 12, LED2 = 13, LED3 = 14, LED4 = 15}LED;

void Led::on(std::initializer_list<LED>& leds)
{
    for (auto& led : leds) // Since this is tagged C++11
    {
        digitalWrite(led, HIGH);
    }
}

Calling this function would be as simple as:

Led::on({LED1, LED2, LED3});

Using an initializer list is good since it lightweight and simple to use. Here is a minimal working example.

Upvotes: 0

Abhishek Kumar
Abhishek Kumar

Reputation: 461

There are a couple of ways to accomplish this.

The most trivial is to use std::vector as mentioned in the comments above.

#include <vector>

void Led::on(std::vector<LED>) {
    for (LED l : leds) {
        digitalWrite(l, HIGH);
    }
}

std::vector<LED> leds = {LED1, LED2};
// you realize you need more
leds.push_back(LED3);

Led::on(leds);

You can use variadic functions. I will neither recommend this nor explain this. I have included a link to help you though.

Upvotes: 0

eerorika
eerorika

Reputation: 238331

For a homogeneous collection of parameters (i.e. objects of same type), the idiomatic way to do this in C++ is to pass a pair of iterators. First iterator to the beginning of a range, and the second iterator to the end (one past the end, to be exact).

Although it would be possible to write a template to handle all input iterators, a simple choice is to support one particular iterator. The choice of iterator depends on what data structure in which you've chosen to store the objects. For example, you could support arrays by using pointer arguments:

void Led::on(LED* begin, LED* end)
{
    std::foreach(begin, end, [](auto& led) {
        digitalWrite(led, HIGH);
    }):
}

Upvotes: 1

Related Questions