简体   繁体   English

如何使用索引访问 C++ struct 属性值?

[英]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" ??如何使用索引而不是使用“a1.name”从 C++ 结构访问和检索值?

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.使用包装类——虽然 C++ 确实增加了结构的灵活性,但它并没有改变它们作为一个简单的异构数据容器的目的。 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.然而,它确实违背了使用 struct 的全部目的,因为您可以只使用普通的非 sturct 类成员来做到这一点,但实际上我在不久前看到它,当时我正在浏览一个 C++ 库,该库包装了以前的 C-基于自身的版本,以便提供更现代的功能,而无需完全重写 C 代码。
  • 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).使用指针遍历数组是一种常见的做法,它的工作原理与此完全一样 - 创建对结构的引用,然后添加 +1、+2、...(结构具有的许多成员)。 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.许多库都提供了这样的容器,例如 Qt 有QVariant (核心模块的一部分), boostboost::variantstd::tuple (甚至更好的命名元组)与标准 C++(自 C++11 起) ) 等等。 I can speak about Qt in greater detail since I have more experience with it.我可以更详细地谈论 Qt,因为我对它有更多的经验。 It offers the QVariantList (a typedef for QList<QVariant> ) which allows indexing.它提供了允许索引的QVariantListQList<QVariant>typedef )。 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.当然,所有这些都要求您 1) 放弃您的结构和 2) 使用一些更高级的容器,这些容器可能会或可能不会对您正在处理的任何事情带来巨大的缺点,包括许可问题、内存开销、更大的二进制文件、处理大量额外的库文件等

How to access C++ struct property value using index?如何使用索引访问 C++ struct 属性值?

You can not.你不能。 C++ language has no feature that would allow this. C++ 语言没有允许这样做的功能。 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.您可以选择使用std::tuple代替,它允许索引成员访问,但由于您无法命名成员,因此可读性下降。

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.一种方法是从成员变量创建一个元组并使用std::tie通过索引获取成员。 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) (至少需要 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:在 C++11 中,除非指定,否则它没有自动返回类型推导,因此您可以使用std::tuple_element来指定返回类型:

#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.直到在 C++ 中引入了反射,在 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.我试图尽可能接近您的示例,但我确实必须将年龄从 int 转换为 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;  
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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