繁体   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
}

如何使用索引而不是使用“a1.name”从 C++ 结构访问和检索值?

你不能。 至少不是以你想要的直接方式去做,也没有部分重新定义结构是什么。 我将把我的答案分成两部分,第一部分解释至少接近你想要的东西的可能方法,第二部分解释你实际应该做什么:

下来和肮脏

有两种方法(我目前可以想出)可能会让您有所思考:

  • 使用包装类——虽然 C++ 确实增加了结构的灵活性,但它并没有改变它们作为一个简单的异构数据容器的目的。 然而,它确实允许运算符重载,包括[]运算符。 因此,如果您创建一个包含结构作为其成员的类(即它环绕结构),则可以使用[]公开结构的数据。 这尽可能接近您想要做的事情。 然而,它确实违背了使用 struct 的全部目的,因为您可以只使用普通的非 sturct 类成员来做到这一点,但实际上我在不久前看到它,当时我正在浏览一个 C++ 库,该库包装了以前的 C-基于自身的版本,以便提供更现代的功能,而无需完全重写 C 代码。
  • 使用带有偏移量的指针- 使用索引通常表明底层容器在其包含的数据块方面具有一致性。 问题是结构不一定遵守这一点,因为它可以包含(就像在您的情况下一样)多种类型的数据。 如果您可以牺牲结构的异构性并坚持使用单一数据类型(例如一个或多个双精度数),您可以安全地使用(直到您必须始终记住结构具有的成员数量)指针以及增加/减少访问其成员的偏移量。 就像创建指向某事物的标准引用(又名指针)时的任何类型的数据一样,该引用指向该数据正在使用的内存开头的地址。 使用指针遍历数组是一种常见的做法,它的工作原理与此完全一样 - 创建对结构的引用,然后添加 +1、+2、...(结构具有的许多成员)。 但是,这使事情变得过于复杂并且容易出错。 如前所述,它还需要在您的结构中使用相同类型的数据。 但是,您也可以创建一组处理(内部)偏移的函数。 但是这个想法类似于我上面提出的类包装器。

替代品...

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

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

你不能。 C++ 语言没有允许这样做的功能。 这在支持(静态)反射的语言中是可能的。

您可以选择使用std::tuple代替,它允许索引成员访问,但由于您无法命名成员,因此可读性下降。

一种方法是从成员变量创建一个元组并使用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;
}

演示

你不能。

直到在 C++ 中引入了反射,在 C++20 中(我希望)应该是这种情况。

一些项目引入了用名称增强的元组,但它仍然不是真正的结构。

我试图尽可能接近您的示例,但我确实必须将年龄从 int 转换为 string。 这有效,我发现它在一个应用程序中很有用。

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