5

我正在使用xsd从 xml 模式文件创建 c++ 代码。对于 xml 类型,会创建多个函数(用于序列化等)。
如果该类型称为XmlType,则会创建以下形式的多个函数:

XmlType XmlType_(const XmlType& a, const string& b)
string XmlType_(const XmlType& a)
...

这是普通函数,不是 XmlType 的成员,它们都具有相同的名称。对于XmlType2,函数将被称为XmlType2_

我想为我的 xml 方案的所有不同 xml 类型编写一个实用程序模板类。不同的功能将被称为洞察这个类。我到目前为止是这样的:

template<typename T>
using TFunc1 = T (*)(const T&, const string&);
template<typename T>
using TFunc2 = string (*)(const T&);

template<typename T, TFunc1<T> func2, TFunc2<T> func2>
class XmlUtil {
... 
}; 

当创建XmlUtil类的实例时,如果必须这样做:

XmlUtil<XmlType, XmlType_, XmlType_> util; 

当我必须将更多函数作为参数传递时,这感觉有点多余并且变得更糟。

我想像这样使用 util 类:

XmlUtil<XmlType, XmlType_> util; 

甚至更好的是这样

XmlUtil<XmlType> util; 

我能想到的唯一方法是以某种方式使用define,但感觉不对。
还有其他方法可以做到这一点吗?

编辑: 我现在使用定义:

#define TRPL(name) name, name ## _, name ## _
...
XmlUtil<TRPL(XmlType)> util;

如果我找到更好的东西,我会编辑这个(也许像 Yakk 在他的回答中建议的那样覆盖集合)。

4

5 回答 5

3

这:

XmlUtil<XmlType> util;

是不可能的,因为没有办法从XmlTypeXmlType_。它们的关系在自动代码生成器之后被丢弃。

然而这:

XmlUtil<XmlType_> util;

可能。您可以推断出函数类型,XmlType_然后使用推断的返回类型将是XmlType. 我相信有为此目的的标准库函数。

至于两种不同的重载,这可能会更棘手。我不认为您可以将函数重载集作为模板参数传递,解析是在模板参数的上下文中对模板参数完成的一个函数。我认为没有办法在不使用预处理器的情况下推迟这个动作。

所以我认为你应该使用#define. 总比没有好。

于 2013-07-12T13:27:08.553 回答
1

这看起来像是覆盖集的工作。

static struct foo_override_set_type {
  template<typename... Args>
  auto operator()( Args...&& args ) const
  ->
    decltype( foo( std::forward<Args>(args)... ) )
  {  return ( foo( std::forward<Args>(args)... ) ); }
  template<typename T>
  operator T() { return foo; }
} foo_override_set;

类型的对象foo_override_set_type表示整个覆盖集foo。调用它们operator()会进行覆盖集查找foo并调用结果函数。将它们转换为函数指针与将标记foo转换为函数指针(或其他值)的作用相同。

您的代码生成可以自动生成此类覆盖集类型。它还可以创建一个特征类,通过特化从您的类型映射XmlType到覆盖的XmlType_函数集。

然后,您可以通过该特征类XmlUtil<XmlType>访问覆盖集。XmlType_它首先实例化覆盖集变量,然后调用()它。

顺便说一句,@Xeo 提出了一个建议,让创建此类对象就像[]XmlType_在 C++1y 或 C++1z 中键入一样简单。

于 2013-07-12T20:23:23.140 回答
0

类定义中的默认模板参数?

template<typename T, TFunc1<T> func1 = XmlType_, TFunc2<T> func2 = XmlType_>
class XmlUtil {
    // ...
};
于 2013-07-12T12:09:07.540 回答
0

您可以使用这样的特征类

template <typename T>
struct Trait{
    typedef T type;
    typedef T (*func1)(const T&, const string&);
    typedef string (*func2)(const T&);
};

并使 XmlUtil 类具有一个模板参数(我们将其命名为 Trait)并使用 Trait::type、Trait::func1 和 Trait::func2。请参阅此处了解完整用法。

在示例中,XmlUtil 的类型如下:

XmlUtil<Trait<XmlType> >

我这样做是因为我不太了解您的问题。可能的情况是您可以直接在 XmlUtil 中定义 Trait 类并使用

 XmlUtil<XmlType>

其他变化是可能的,它只取决于你需要什么。

您可以在此处阅读 trait 类的简要介绍。如果您想阅读有关此主题的更多信息,我建议您使用 Modern C++ (Alexandrescu)。

于 2013-07-12T12:11:50.033 回答
0

我不确定我是否完全理解您的要求。序列化和反序列化的常用方法是创建工厂(抽象工厂)并动态解析对象的构造。请注意,这可以针对复杂结构进行改进,其中代码生成器可以创建成员函数来提取每个成员的确切类型。

但同样,我不完全理解你真正想要做什么......作为建议,我相信如果你提供更多关于要解决的问题的描述会有所帮助,因为问题的重点是如何制定你的解决方案工作,并且隐含地丢弃了可能是更好设计的其他方法。

于 2013-07-12T12:46:05.463 回答