有没有办法在成员名称循环中对N C++类成员应用操作(可能通过预处理器)?

DVK*_*DVK 7 c++ reflection c-preprocessor

问题:

我有一个带有gajillion(> 100)成员的C++类,它们的行为几乎相同:

  • 相同的类型

  • 在函数中,每个成员具有与其他成员相同的完全代码,例如,从构造函数中的映射赋值,其中map键与成员键相同

  • 在许多函数(> 20)中重复这种行为的相同性,当然每个函数中的行为是不同的,所以没有办法解决问题.

  • 成员列表非常流畅,具有不断添加和有时删除,一些(但不是全部)由更改DB表中的列驱动.

您可以想象,就代码创建和维护而言,这是一个很大的痛苦,因为要添加新成员,您必须为使用类似成员的每个函数添加代码.

我想要的解决方案示例

我需要的实际C++代码(例如,在构造函数中):

MyClass::MyClass(SomeMap & map) { // construct an object from a map 
    intMember1 = map["intMember1"];
    intMember2 = map["intMember2"];
    ... // Up to 
    intMemberN = map["intMemberN"];
}
Run Code Online (Sandbox Code Playgroud)

我希望能够编写的C++代码:

MyClass::MyClass(SomeMap & map) { // construct an object from a map 
#FOR_EACH_WORD Label ("intMember1", "intMember2", ... "intMemberN")
    $Label = map["$Label"];
#END_FOR_EACH_WORD
}
Run Code Online (Sandbox Code Playgroud)

要求

  • 该解决方案必须与GCC兼容(如果重要的话,使用Nmake作为make系统).不关心其他编译器.

  • 解决方案可以是预处理器级别,也可以是可编译的.我对任何一个都很好; 但是到目前为止,我的所有研究都指出了这样的结论:后者在C++中显然是不可能的(我现在想念Perl,因为我被迫做C++!)

  • 解决方案必须至少在某种程度上是"行业标准"(例如Boost很棒,但Joe-Quick-Fingers创建一次并在他的博客上发布的自定义Perl脚本不是.哎呀,我可以很容易地写出Perl脚本,更像是Perl专家而不是C++专家 - 我只是无法让我的BigCompany的软件工程大佬们购买使用它:))

  • 解决方案应该允许我声明一个ID列表(理想情况下,只在一个头文件中而不是在每个"#FOR_EACH_WORD"指令中,就像我在上面的示例中所做的那样)

  • 解决方案不能仅限于"从DB表创建对象"构造函数.有许多功能,其中大多数不是构造函数,需要它.

  • 解决方案"在一个向量中创建所有值,然后在向量上运行'for循环"是一个明显的解决方案,并且无法使用 - 许多应用程序使用的库中的代码,成员是公共的遗憾的是,重写这些应用程序以使用向量成员而不是命名成员是不可能的.

Boj*_*nik 9

Boost包含一个很棒的预处理器库,您可以使用它来生成这样的代码:

#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/cat.hpp>

typedef std::map<std::string, int> SomeMap;

class MyClass
{
public:
    int intMember1, intMember2, intMember3;

    MyClass(SomeMap & map) 
    {
        #define ASSIGN(z,n,_) BOOST_PP_CAT(intMember, n) = map[ BOOST_PP_STRINGIZE(BOOST_PP_CAT(intMember, n))];
        BOOST_PP_REPEAT_FROM_TO(1, 4, ASSIGN, nil)
    }
};
Run Code Online (Sandbox Code Playgroud)


Luc*_*lle 6

Boost.Preprocessor提出了许多方便的宏来执行这样的操作.Bojan Resnik已经提供使用此库的解决方案,但它假定每个成员名称的构造方式相同.

由于您明确要求可能声明ID列表,因此这里有一个解决方案可以更好地满足您的需求.

#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>

// sequence of member names (can be declared in a separate header file)
#define MEMBERS (foo)(bar)

// macro for the map example
#define GET_FROM_MAP(r, map, member) member = map[BOOST_PP_STRINGIZE(member)];

BOOST_PP_SEQ_FOR_EACH(GET_FROM_MAP, mymap, MEMBERS)
// generates
// foo = mymap["foo"]; bar = mymap["bar];

-------

//Somewhere else, we need to print all the values on the standard output:
#define PRINT(r, ostream, member) ostream << member << std::endl;

BOOST_PP_SEQ_FOR_EACH(PRINT, std::cout, MEMBERS)
Run Code Online (Sandbox Code Playgroud)

如您所见,您只需要编写一个表示要重复的模式的宏,并将其传递给BOOST_PP_SEQ_FOR_EACH宏.