简体   繁体   中英

How to access C++ struct property value using index?

struct student {
    string name;
    int age;
};

int main() {
    student a1;

    cout << a1[0] << endl;  //Access the first variable of the struct
    cout << a2[1] << endl;  //Access the first variable of the struct
}

How could I access and retrieve value from the C++ struct using index instead of using "a1.name" ??

You can't. At least not in the direct manner you want to do it and without partially redefining what a structure is. I will split my answer into two parts the first one explaining possible ways to get at least close to what you want and the second one explaining what you actually should do:

Getting down and dirty

There are two ways (that I can currently come up with) that might give you something to think about:

  • Use a wrapper class - while C++ does increase the flexibility of structure it doesn't change their purpose of a simple heterogeneous data container. It does however allow operator overloading including the [] operator. So if you create a class that contains the structure as its member (that is it wraps around the structure), you can expose the structure's data using [] . This comes as close to what you want to do as possible. It does however defeat the whole purpose of using a struct since you can do that with just plain non-sturct class members but I have actually seen it not so long time ago when I was going through a C++ library that was wrapping a previous C-based version of itself in order to provide more modern features without the need of completely rewriting the C code.
  • Use pointer with an offset - using indexing generally suggest that the underlying container has a consistency when it comes to the blocks of data it contains. The problem is that a structure doesn't necessarily obey this since it can contain (just like in your case) multiple types of data. If you can sacrifice the heterogeneity of your structure and stick with a single data type (for example one or more doubles), you can safely use (up to the point that you have to always remember the number of members the structure has) a pointer and an increasing/decreasing offset to access its members. Just like with any sort of data when you create a standard reference (aka pointer) to something, that reference points at the address of the beginning of the memory this data is using. It is a common practice to use pointers to iterate through arrays and it works exactly like that - create a reference to your structure and the add +1, +2, ... (as many members that struct has). This makes things overly complicated though and is prone to error. As mentioned it also requires using the same type of data inside your structure. However you can also create a set of functions that handle (internally) the offsets. But this idea is similar to the class wrapper I have proposed above.

The alternatives ...

From what you have given as information I think you are looking for a completely different type of data - a dictionary, map or a list that contains some sort of custom generic data container that can hold any type of data but also stores that data's type in order to allow recasting it to its original state. Many libraries provide such containers for example Qt has the QVariant (part of the core module), boost has the boost::variant , std::tuple (or even better - named tuples) provided with your standard C++ (since C++11) and so on. I can speak about Qt in greater detail since I have more experience with it. It offers the QVariantList (a typedef for QList<QVariant> ) which allows indexing. Of course all this requires you to 1)abandon your structure-thing and 2)use some more advanced containers that may or may not introduce huge drawbacks on whatever you are working on including licensing issues, memory overhead, larger binaries, handling a lot of extra library files etc.

How to access C++ struct property value using index?

You can not. C++ language has no feature that would allow this. This could be possible in a language that supports (static) reflection.

You could choose to use a std::tuple instead, which does allow indexed member access, but that's a step down in readability since you don't get to name the members.

One way to do this is by creating a tuple from the member variables and using std::tie to get at the member by index. The index would have to be known at compile time however. You could wrap this inside a member function of your struct:

#include <tuple>
#include <iostream>

struct student {
    std::string name;
    int age;

    template<size_t I>
    auto& get() {
        return std::get<I>(std::tie(name, age));
    }

};

int main() {
    student boy{ "Paul", 12 };
    std::cout << "Name: " << boy.get<0>() << " Age: " << boy.get<1>() << std::endl;

    //Change members
    boy.get<0>() = "John";
    boy.get<1>() = 14;
    std::cout << "Name: " << boy.get<0>() << " Age: " << boy.get<1>() << std::endl;
}

Demo

(Requires at least C++14)


In C++11, since it doesn't have automatic return type deduction unless specified, you could use std::tuple_element to specify the return type instead:

#include <tuple>
#include <iostream>

struct student {
    std::string name;
    int age;

    template<size_t I>
    using T = typename std::tuple_element<I, std::tuple<std::string, int>>::type;

    template<size_t I>
    T<I>& get()
    {
        return std::get<I>(std::tie(name, age));
    }    
};

int main() {
    student boy{ "Paul", 12 };
    std::cout << "Name: " << boy.get<0>() << " Age: " << boy.get<1>() << std::endl;

    //Change members
    boy.get<0>() = "John";
    boy.get<1>() = 14;
    std::cout << "Name: " << boy.get<0>() << " Age: " << boy.get<1>() << std::endl;
}

Demo

You cannot.

Not until reflection has been introduced in C++, which should (I hope) be the case in C++20.

Some projects introduce tuples enhanced with names, but it still not real structs.

I tried to stay as close to your example as possible but I did have to convert the age from int to string. This works and I have found it useful in one application.

struct student 
{
    std::string name, age;
    std::string *elemtnPtr[10];
    student()
    {
        int i=0;
        elemtnPtr[i++] = &name;
        elemtnPtr[i++] = &age;
    }
};
void demo()
{
    student a1;
    a1.name = "This Works";
    a1.age = "99";
    std::cout << *a1.elemtnPtr[0] << std::endl;  
    std::cout << *a1.elemtnPtr[1] << std::endl;  
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM