Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++, passing struct features into function as a parameter

First of all, I would like to say this is the first question I am asking on stackOverflow, so I apologize if I am not clear enough.

My question regards referring parametrically to a struct feature inside a function. I work in C++.

What I really want to achieve is to be able to sort a vector of struct objects (or class objects) based on a specific struct feature, which is given as a parameter. I also want to give the type of struct through a template, so some workarounds that deal with specific situations might not work in general.

I will show a simplistic example of what I mean.

Let's say, I have a struct called "human" with features: "age", "height", "weight".

Let's also assume that I have a vector of "human" objects called "mankind".

Here, let's say I want to make a function that can output to the screen each element's age, height or weight, depending on what I pass as a parameter.

The code below obviously doesn't work. I am asking for the proper way to do this.

struct human{
    int age;
    int height;
    int weight;
};

void show(vector<human> &elements, int value){
    for (int i=0; i<elements.size(); i++)
        cout << elements[i].value << endl;
}

int main{
    ...
    vector<human> mankind;
    ...
    show(mankind, age);
    show(mankind, height);
    show(mankind, weight);
    ...
    return 0;
}

I want to point out, that this example is a very simple case. Of course, I can make this work if I make separate functions for each feature or if I use a cheeky way, like passing a string "age" or "height" or "weight" as a parameter, checking it inside the function and having a completely separate case for each one.

However, such workarounds won't work in the general case of the problem, especially if I have many different types of structs (passed through a template T and vector< T > ) and features.

like image 726
New Guy Avatar asked Dec 28 '18 19:12

New Guy


People also ask

Can we pass structure as a function argument?

Structures can be passed as function arguments like all other data types. We can pass individual members of a structure, an entire structure, or, a pointer to structure to a function. Like all other data types, a structure or a structure member or a pointer to a structure can be returned by a function.

Can we pass structures to a function in C?

C Structure and Function Similar to variables of built-in types, you can also pass structure variables to a function.

Can you pass an entire structure to function?

Passing of structure to the function can be done in two ways: By passing all the elements to the function individually. By passing the entire structure to the function.

How to pass a structure to a function in C?

Passing structure to function in C: It can be done in below 3 ways. Passing structure to a function by value Passing structure to a function by address(reference) No need to pass a structure – Declare structure variable as global

How to pass structure as an argument to the function?

How to pass structure as an argument to the functions? Passing of structure to the function can be done in two ways: By passing all the elements to the function individually. By passing the entire structure to the function. In this article, entire structure is passed to the function.

How to call a function from a structure as a parameter?

Please read our previous article, where we discussed Array as Parameter. If we are sending a structure as a parameter to a function, it may be called by value or call by address, call by reference is there in C++ also.

What does it mean to pass a structure by value?

In this program, the whole structure is passed to another function by value. It means the whole structure is passed to another function with all members and their values. So, this structure can be accessed from called function.


Video Answer


2 Answers

One way to do this is to use pointers-to-members, a C++ feature that lets you create pointers that refer to specific fields of a struct or class.

The syntax here might look a little scary, but it's actually not so bad. For example, here's how you'd get a pointer to the height field of your human struct:

int human::* ptr = &human::height;

Here, the syntax int human::* ptr means

  1. that it's a pointer to something inside the human type;
  2. specifically, it's a pointer to an int data member; and
  3. that data member is the height field.

Once you have this pointer, you can combine it with a human struct to isolate out just that member like this:

human agatha;
cout << agatha.*ptr << endl;

Here, the .* operator means "pull up the field pointed at by ptr.

In your case, you might put things together like this:

void show(vector<human> &elements, int human::* value){
    for (int i=0; i<elements.size(); i++)
        cout << elements[i].*value << endl;
}

int main{
    ...
    vector<human> mankind;
    ...
    show(mankind, &human::age);
    show(mankind, &human::height);
    show(mankind, &human::weight);
    ...
    return 0;
}
like image 138
templatetypedef Avatar answered Oct 06 '22 13:10

templatetypedef


I prefer the lambda approach to this problem. If the function doesn't know what will be printed, just the calling code, then you can pass a lambda to the function that contains the code of what to print. That way you can make the function completely generic like

template <typename T, typename Func>
void show(vector<T> const& elements, Func f){
    for (auto const& e : elements)
        cout << f(e)<< endl;
}

and then you would call it like

show(mankind, [](auto const& e){return e.age;});
show(mankind, [](auto const& e){return e.height;});
show(mankind, [](auto const& e){return e.weight;});

If show needs to show this member in order then you can even leverage the lambda in you call to std::sort like

template <typename T, typename Func>
void show(vector<T>& elements, Func f){
    std::sort(elements.begin(), elements.end(), [=](auto const& lhs, auto const& rhs){return f(lhs) < f(rhs);});
    for (auto const& e : elements)
        cout << f(e)<< endl;
}

So the element to print is used to the sort vector and to print the element.

like image 3
NathanOliver Avatar answered Oct 06 '22 14:10

NathanOliver