没有__VA_ARGS__的变量宏

时间:2014-02-06 15:53:40

标签: c++ c-preprocessor variadic

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

#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和两个整数,class 3可以用两个构造布尔等...)。

所有这些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”类的成员函数,如果不可用则引发异常(即,文件中不存在),否则返回值(从文件读取)。

类“字段”也有一个重载运算符>>,它应用标准运算符>>在值上,并将布尔属性设置为true。

由于模型太多,我想在宏中转换代码: - )

1 个答案:

答案 0 :(得分:0)

我不确定你是否有自由改变你的实施方式,就像我即将提出的那样,但这就是我要做的。它不需要任何奇特的模板技术。

首先,创建一个名为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 - 类型,您可以从中导出所有其他类型,例如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");
        }
    }
};

希望这有帮助。

相关问题