How write *same* function to work with different elements of a struct


The struct in this case stores pixel data related to different components something like this:

typedef struct RGB
{
int blue;
int green;
int red;
} RGB;

RGB pixel_data[256][512];

The code processes the blue pixel data by accessing element blue, then doing same steps on element green and then on element red. I can write three different functions in which I access only pixel_data[y][x].blue then another function where pixel_data[y][x].green is accessed and finally one where pixel_data[y][x].red is accessed.

Since the three functions are very similar except these details, I am wondering if I can have a single function which can be called with a parameter specifying which color component to process. Is there a way to do this?

The struct is same for three functions so having void* is not needed. I could e.g use int* to pixel_data[y][x] and then do pointer arithmatic on that to access different components? Is this the best way to do this? Are there other ways?
How you write your function/s really depends on what the function/s are doing. But if you're function is just going to access one element of your pixel_data array at a time and the "math" is the same regardless of the color then you could just call the same function three times for each of the colors.

a (scoped) enum might be one alternative:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# include <iostream>

enum class Color {BLUE, GREEN, RED};

void tellColor (const Color& c)
{
    if(c == Color::BLUE)std::cout << "blue \n";
    if (c == Color::GREEN)std::cout << "green \n";
    if (c == Color::RED)std::cout << "red \n";
}

int main()
{
    auto c = Color::GREEN;
    tellColor(c);
}
c++ lets you declare structs like classes.

struct name
{
members;
};

name x

the old name at the end mess is a leftover from C that IMHO looks ugly and serves no function anymore.

Also, wouldn't RGB be bytes? I know of a few places where you might use more bits, like hyperspectral data, but most graphics and images still use 4 bytes (RGBA) format, so you are wasting a ton of memory if you don't need the extra space.

This isnt related to your issue, just a little cleanup that might help long term.


Also, for the dominate color issue ... I would use 1 byte for that also.
Just set it to 'r' 'g' or 'b'. Or you can do 1,2,4 and check it with a bitwise logic. Whatever you prefer. If you need the human output, you can do

char domcolor; //inside your struct maybe??

string colornames[3] = {"RED", "GREEN", "BLUE"};
... set domcolor as above if statements
..
cout << colornames[?.domcolor];

Something like that?

Last edited on
three functions are very similar except these details


If you have something that is "similar except xxx", the most direct thing to consider if whether xxx can become a parameter.

There are a few ways to deal with that, but if you don't want to touch your struct, give member pointers a try:

They can be compile-time parameters:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
struct RGB // don't typedef, that's gross
{
  int blue;
  int green;
  int red;
};
RGB pixel_data[256][512];

template<int(RGB::*PX)>
int inc_pixel(RGB& rgb) {
    return (rgb.*PX)++;
}

int main() {
  for(auto& row: pixel_data)
    for(RGB& px : row) {
      inc_pixel<&RGB::red>(px);
      inc_pixel<&RGB::green>(px);
      inc_pixel<&RGB::blue>(px);
      std::cout << " pixel is now " << px.red << ',' << px.green << ',' << px.blue << '\n';
    }
}


...or run-time parameters:
1
2
3
4
5
6
7
8
9
10
11
12
13
int inc_pixel(RGB& rgb, int RGB::*px) {
    return (rgb.*px)++;
}

int main() {
  for(auto& row: pixel_data)
    for(RGB& px : row) {
      inc_pixel(px, &RGB::red);
      inc_pixel(px, &RGB::green);
      inc_pixel(px, &RGB::blue);
      std::cout << " pixel is now " << px.red << ',' << px.green << ',' << px.blue << '\n';
    }
}




Last edited on
Topic archived. No new replies allowed.