簡體   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