Variadic Macro without __VA_ARGS__

Variadic Macro without __VA_ARGS__

本文关键字:VA ARGS without Macro Variadic      更新时间:2023-10-16

所以,这基本上就是我要做的:

#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是一类(因此宏中的最后命令是构造函数调用)。

关键是:假设我有二十个不同的类,每个类都需要一个不同的输入才能构造。

宏接收类的名称和构建此类对象所需的参数的名称。

关键是(请参阅下面的"设计原因"),我需要在" if"条件下使用参数的名称。这就是为什么我使用宏(具有#和##特殊字符的不错功能)而不是模板函数的原因。

基本上,我需要一个纯文本转换(因此是宏,而不是函数),但是有一个可变的参数名称。


此设计的原因

让我们假设我有二十种不同的类,一个与另一个类别有很大不同(例如,可以用两个双double构建1类布尔等...)。

所有这些classe都具有"运行"成员函数,该功能产生相同格式的输出。

我的程序应执行以下操作:

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成员(存储一个值)和一个布尔成员(告诉我是否存在变量)

2-创建一个具有许多"字段"的对象(读取器,读取文件的对象),一个用于每个可能的模型属性(_name,_name,_speed,_male等。)

3-然后,在阅读文件时,对于括号内的部分,我首先读取一个字符串("标签"),然后读取" =",最后我读取该值。该值将以字符串的相同名称

存储在变量中

(如果我找到了" speed = 0.03"行,我将在读者的字段中保存0.03)。

这应该是伪代码(可能有ERROS;仅出于说明目的):

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()是"字段"类的成员函数,如果不可用(即,在文件中不存在),或返回值(从文件中读取)。

类"字段"还具有超载的操作员>>,该操作员在值上应用标准运算符>>,并将其设置为true boolean属性。

由于模型太多了,我想在宏中进行代码: - )

我不确定您是否可以自由地像我要提出的那样大幅度地更改实现,但这是我要做的。它不需要任何异国情调的模板技术。

首先,您创建一个称为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构造函数 Will

现在,您定义了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");
        }
    }
};

希望这会有所帮助。