我正在开发能够用 C++ 描述一些 XML 文件的语义的数据结构。想法是检查各种元素的存在和/或正确顺序,同时将它们包含的文本存储到 QHash 对象中,其中 QString id(基于元素名称,但可自定义)作为键。
由于 XML 支持嵌套,我希望能够反映这种嵌套。所以每个 XML 元素要么由“名称”和(可选)“id”描述,这意味着它是最终的叶子,它的文本将被解析,或者“名称”和其他元素描述符的列表,这意味着应该有这些当前元素内的嵌套元素。
由于会有很多这样的语义方案,我希望描述它们的各个实例的代码非常紧凑。
我的想法是有一个类,它描述一个元素并且可以通过 c++ std::initializer_list 文字构造,我希望隐式支持嵌套。各种重载的构造函数,以后可以设置各种特定的细节。
我快到了,但现在卡住了。即使constructor(std::initializer_list<ProtocolDescriptorTestNode >);
对于每个嵌套的花括号,通常都会调用带有签名的构造函数,但constructor(QString, std::initializer_list<ProtocolDescriptorTestNode >);
永远不会调用类似的签名构造函数,即使我将构造像{ "xyz", { {"abc", "123"}, {"def","456"} } }
初始化器文字那样放置。
请查看以下与测试代码分开的代码片段并帮助我理解:
1. 这是正常的 c++11 行为,std::initializer_list 不支持这种与其他数据类型参数结合的嵌套。
2. 这是 gcc 中的实现问题(bug ;))(我使用的是 4.9.1 版(Debian 4.9.1-1))
3. 我忽略了代码语法/语义中的一些非常愚蠢的细节。
类声明(相关构造函数摘录):
class ProtocolDescriptorTestNode {
public:
ProtocolDescriptorTestNode(const ProtocolDescriptorTestNode&);
ProtocolDescriptorTestNode(std::initializer_list<ProtocolDescriptorTestNode > init); // 1
ProtocolDescriptorTestNode(QString name, std::initializer_list<ProtocolDescriptorTestNode > init); // 2
ProtocolDescriptorTestNode(QString name, QString id, enum eElementMode = modeDefault); // 4
ProtocolDescriptorTestNode(QString name, enum eElementMode = modeDefault); //5
~ProtocolDescriptorTestNode() {}
QString name, id;
tProtocolDescriptorTestList list;
};
相关构造函数的定义:
ProtocolDescriptorTestNode::ProtocolDescriptorTestNode(std::initializer_list<ProtocolDescriptorTestNode> init)
{
qDebug() << "*** CONSTRUCTOR CALLED - 1 *** ";
qDebug() << init.size();
for(ProtocolDescriptorTestNode x : init) {
qDebug() << x.name << x.id;
}
}
ProtocolDescriptorTestNode::ProtocolDescriptorTestNode(QString name, std::initializer_list<ProtocolDescriptorTestNode> init) {
qDebug() << "*** CONSTRUCTOR CALLED - 2 *** ";
qDebug() << init.size();
for(ProtocolDescriptorTestNode x : init) {
qDebug() << x.name << x.id;
}
}
ProtocolDescriptorTestNode::ProtocolDescriptorTestNode(QString name, QString id, enum eElementMode) :
name(name),
id(id)
{
qDebug() << "*** CONSTRUCTOR CALLED - 4 *** ";
qDebug() << name << id;
}
ProtocolDescriptorTestNode::ProtocolDescriptorTestNode(QString name, enum eElementMode) :
name(name),
id("***")
{
qDebug() << "*** CONSTRUCTOR CALLED - 5 *** ";
qDebug() << name << id;
}
测试对象实例:(注意:隐式/显式数据类型转换 char * / QString 没有区别)
ProtocolDescriptorTestNode groupOther
({
{QString("name1"),"groupOther1"},
{"name2","groupOther2"},
{ QString("B"), {
{"name3","groupOther3"},
{
{"intra1","a"},
{QString("intra2")}
},
{"name4","groupOther4"}
} }
});
以及调试输出的相关部分,显示靠近"B"
文字的初始化部分被视为node(QString("B")
并node(std::initializer_list)
连接,而不是node(QString("B"), std::initializer_list)
我的意图:
*** CONSTRUCTOR CALLED - 4 ***
"name1" "groupOther1"
*** CONSTRUCTOR CALLED - 4 ***
"name2" "groupOther2"
*** CONSTRUCTOR CALLED - 5 ***
"B" "***"
*** CONSTRUCTOR CALLED - 4 ***
"name3" "groupOther3"
*** CONSTRUCTOR CALLED - 4 ***
"intra1" "a"
*** CONSTRUCTOR CALLED - 5 ***
"intra2" "***"
*** CONSTRUCTOR CALLED - 1 ***
1
"intra2" "***"
*** CONSTRUCTOR CALLED - 1 ***
2
"intra1" "a"
"" ""
*** CONSTRUCTOR CALLED - 4 ***
"name4" "groupOther4"
*** CONSTRUCTOR CALLED - 1 ***
3
"name3" "groupOther3"
"" ""
"name4" "groupOther4"
*** CONSTRUCTOR CALLED - 1 ***
2
"B" "***"
"" ""
*** CONSTRUCTOR CALLED - 1 ***
3
"name1" "groupOther1"
"name2" "groupOther2"
"" ""