如何使用索引访问C 结构属性值

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

本文关键字:结构 属性 访问 何使用 索引      更新时间:2023-10-16
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
}

我如何使用索引从C 结构中访问和检索值是通过从成员变量创建元组并使用std::tie通过索引获得成员。但是,必须在编译时知道该索引。您可以将其包装在结构的成员功能中:

#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;
}

演示

(至少需要C 14)


在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

你不能。至少不是直接您想做的,而没有部分重新定义结构是什么。我将把答案分为两个部分,解释了至少接近您想要的东西的可能方法,第二个解释了您实际应该做的事情:

下降和肮脏

有两种方法(我目前可以提出)可能会给您一些考虑:

  • 使用包装类别类 - 而C 确实会增加结构的灵活性,但它不会改变其目的,而简单的异质数据容器的目的。但是,它确实允许运算符重载,包括[]操作员。因此,如果创建一个包含结构作为其成员的类(即它围绕结构包裹),则可以使用[]公开结构的数据。这与您想做的事情尽可能接近。但是,它确实打败了使用结构的全部目的,因为您只能使用普通的非strct类成员来做到这一点,但是我实际上已经看到了很长时间之前,当我经过一个C 库,该库包裹了以前的C-基于自身的版本,以提供更现代的功能而无需完全重写C代码。
  • 使用带有偏置的指针 - 使用索引通常表明,基础容器在其中包含的数据块时具有一致性。问题在于结构不一定遵守这一点,因为它可以包含多种类型的数据(就像您的情况下一样)。如果您可以牺牲结构的异质性并使用单个数据类型(例如一个或多个双打),则可以安全地使用(直到您必须始终记住结构的成员数量)以及访问其成员的增加/减少偏移。就像在创建标准参考(aka指针)时使用任何类型的数据一样,将其引用指向该数据使用的内存开始的地址。使用指针通过数组迭代是一种常见的做法,并且它与此类完全奏效 - 对您的结构以及add 1, 2,...(与许多结构成员一样)进行引用。但是,这使事情过于复杂,并且容易出错。如前所述,它还需要使用结构内的相同类型的数据。但是,您还可以创建(内部)偏移(内部)处理的一组功能。但是这个想法类似于我上面提出的类包装器。

替代方案...

根据您的信息,我认为您正在寻找完全不同类型的数据 - 字典,地图或包含某种自定义通用数据容器的词典,地图或列表,该容器可以容纳任何类型的数据,还存储数据类型是为了允许将其重新铸造到其原始状态。许多库提供了这样的容器,例如QT具有QVariant(核心模块的一部分),boost具有带有标准C (自C 11)等提供的boost::variantstd::tuple(甚至更好 - 命名为单元)。我可以更详细地谈论QT,因为我有更多的经验。它提供允许索引的QVariantListQList<QVariant>typedef)。当然,所有这些都需要您到1)放弃结构 - 2)使用一些更高级的容器,这些容器可能会或可能不会在您正在从事的任何工作中引入巨大的缺点,包括许可问题,内存开销,较大的二进制文件,处理很多额外的库文件等

如何使用索引访问C 结构属性值?

你不能。C 语言没有允许此功能的功能。这可能是一种支持(静态)反射的语言。

您可以选择使用std::tuple,这确实允许索引成员访问,但这是可读性降低的,因为您没有命名成员。

你不能。

直到在C 中引入反射之前,我希望(我希望)在C 20中是这种情况。

一些项目介绍了用名称增强的单元,但它仍然不是真实的结构。

我试图保持尽可能靠近您的示例,但我确实必须将年龄从int转换为字符串。这起作用了,我发现它在一个应用程序中很有用。

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;  
}