簡體   English   中英

沒有__VA_ARGS__的變量宏

[英]Variadic Macro without __VA_ARGS__

所以,這基本上就是我想做的事情:

#define RS03(obj, a1, a2, a3) {if (_str1 == #a1) _file >> _##a1; if (_str1 == #a2) _file >> _##a2;if (_str1 == #a3) _file >> _##a3; obj (_##a1, _##a2, _##a3);}

這是三個論點的情況,但我還需要:

#define RS04(obj, a1, a2, a3, a4)
#define RS05(obj, a1, a2, a3, a4, a5)
#define RS06(obj, a1, a2, a3, a4, a5, a6)
...

所以一個可變宏。

關於此主題的Stackoverflow有很多問題,但它們不適用於我的情況。

在上面的代碼中,三個參數a1,a2和a3既用作字符串(在“if”條件中)又用作變量(在賦值和構造函數中),而obj是一個類(所以最后一個命令在宏是一個構造函數調用)。

關鍵是:假設我有20個不同的類,要求每個類都有不同數量的輸入來構造。

宏接收類的名稱以及構建此類對象所需的參數名稱。

關鍵是(參見下面的“設計原因”)我需要在“if”條件下使用參數的名稱,就像字符串一樣。 這就是我使用宏(具有#和##特殊字符的優點)而不是模板函數的原因。

基本上,我需要一個純文本轉換(所以一個宏,而不是一個函數),但有一個變量名稱的參數。


這種設計的原因

讓我們假設我有20個不同的類,每個類與另一個非常不同(例如,類1可以用兩個double構造,類2需要一個double和兩個整數,類3可以用兩個bool構造,等等...)。

所有這些classe都有一個“run”成員函數,它產生相同格式的輸出。

我的程序應該執行以下操作:

1 - 讀取文本文件

2 - 為文件中描述的每個模型啟動運行

該文件應該是這樣的:

car {
    name = model1
    speed = 0.05
}

man {
    name = model2
    speed = 0.03
    male = true
    ageclass = 3
}

...

所以我需要讀取這樣的文件並初始化文件中描述的每個類。

參數應按用戶喜歡的順序編寫。

此外,它們可能會出現不止一次,例如:

car {
    name = pippo
    speed = 0.05
    speed = 0.06
    speed = 0.07
}

(在這種情況下,最后一個將覆蓋另一個)

如果用戶忘記了某些參數,程序應該以明確的錯誤消息停止。

可能存在相同類型的不同模型(例如,4個不同的平面模型)。

例如,在這種情況下:

car {
    name = pippo
    speed = 0.05
}

car {
    name = pluto
}

該計划應該說第二個模型是不完整的。

當然有很多方法可以做到這一點。

我這樣做:

1 - 使用T成員(存儲值)和bool成員(告訴我變量是否存在)創建模板類(讓我們稱之為“字段”)

2 - 使用多個“字段”創建一個對象(讀取器,讀取文件的對象),每個可能的模型屬性一個(_name,_speed,_male等...)

3 - 然后,在讀取文件時,對於括號內的部分,我首先讀取一個字符串(“標簽”),然后我讀取“=”,最后我讀取了值。 該值將存儲在具有相同名稱的變量中

(如果我找到“speed = 0.03”這一行,我將在讀者的字段_name中保存0.03)。

這應該是偽代碼(可能有錯誤;它僅用於說明目的):

if (car) {
    while (str != "}") {
        if (str == "speed")    { _file >> _speed;     _file >> _str; }
        if (str == "male")     { _file >> _male;      _file >> _str; }
        if (str == "ageclass") { _file >> _ageclass;  _file >> _str; }
        ERROR;
    }
    car (_speed.get (), _male.get (), _ageclass.get ());
}

get()是“field”類的成員函數,如果不可用則引發異常(即,文件中不存在),否則返回值(從文件讀取)。

類“field”還有一個重載的運算符>>,它在值上應用標准運算符>>,並將布爾屬性設置為true。

由於模型很多,我想在宏中轉換代碼:-)

我不確定你是否可以自由地改變你的實現,就像我即將提出的那樣,但這就是我要做的。 它不需要任何奇特的模板技術。

首先,創建一個名為Properies的結構(例如),它包含任何類可以禁止的所有屬性。

struct Properties
{
    enum Types
    {
        MAN,
        CAR,
        // and more                                                                              
    };

    enum Gender
    {
        MALE, FEMALE
    };

    Types type;
    string name;
    double speed;
    Gender gender;
    int ageClass;
};

如您所見,它還包含一個描述每個現有類型的enum

接下來,您定義一個Base -type,從中派生所有其他類型,如ManCar等。

class Base
{};

class Man: public Base
{
    string d_name;
    Properties::Gender d_gender;
    int d_ageClass;
    double speed;

public:
    Man(Properties const &properties)
    {
        // Set properties that apply to the "Man"-class                                          
    }
};

class Car: public Base
{
    string d_name;
    double d_speed;

public:
    Car(Properties const &properties)
    {
        // Set properties that apply to the "Car"-class                                          
    }
};

每個類的構造函數都需要一個Properties對象,從中可以提取適合它們的字段。 例如, Car構造函數不會檢查gender字段,而Man構造函數將檢查

現在,您定義一個Loader類來處理解析。 它包含一個成員readFile ,它返回一個Base*向量,這樣你就可以指向一個容器中的所有初始化對象。 我選擇使用shared_ptr來處理所有權問題,但您應該決定什么是最適合您的應用程序。

class Loader
{
public:
    static vector<shared_ptr<Base>> readFile(string const &fileName)
    {
        vector< shared_ptr<Base> > result;
        ifstream file(fileName);
        // Parse the file, creating a "Properties" object, called                                
        // "props" here                                                                          

        while (file) // while EOF not reached.                                                   
        {
            Properties props = parse(file); // implement your parse                              
                                            // routine, returning Properties.                    
            switch (props.type)
            {
            case Properties::CAR:
                result.push_back(shared_ptr<Base>(new Car(props)));
                break;
            case Properties::MAN:
                result.push_back(shared_ptr<Base>(new Man(props)));
                break;
            // etc for all classes derived from Base                                             
            default:
                throw string("error: unknown type");
        }
    }
};

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM