我正在使用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在他的回答中建议的覆盖集)。
答案 0 :(得分:3)
此:
XmlUtil<XmlType> util;
是不可能的,因为无法从XmlType
转到XmlType_
。他们的关系在自动代码生成器之后被丢弃。
但是这个:
XmlUtil<XmlType_> util;
可能。您可以推导出XmlType_
的函数类型,然后使用推导的返回类型XmlType
。我相信有这个目的的标准库函数。
对于两个不同的重载,这可能比较棘手。我不认为你可以将函数重载集作为模板参数传递,解析是在模板参数的上下文中的模板参数上完成一个函数。我不认为有一种方法可以在不使用预处理器的情况下推迟此操作。
所以我认为你应该使用#define
。它总比没有好。
答案 1 :(得分: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
转换为函数指针(或其他值)的方法相同。
您的代码生成可以自动生成此类覆盖集类型。它还可以创建一个traits类,通过专门化从您的类型XmlType
映射到覆盖XmlType_
函数集。
然后,您的XmlUtil<XmlType>
可以通过该特征类访问XmlType_
的覆盖集。它首先实例化覆盖集变量,然后在其上调用()
。
顺便说一下,@ Xeo有一个建议,就像在C ++ 1y或C ++ 1z中输入[]XmlType_
一样简单地创建这样的对象。
答案 2 :(得分:0)
类定义中的默认模板参数?
像
template<typename T, TFunc1<T> func1 = XmlType_, TFunc2<T> func2 = XmlType_>
class XmlUtil {
// ...
};
答案 3 :(得分: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。有关完整用法,请参阅here。
在示例中,XmlUtil的类型如下:
XmlUtil<Trait<XmlType> >
我这样做是因为我不太了解你的问题。可能是您可以直接将Trait类定义到XmlUtil并使用
XmlUtil<XmlType>
其他变体是可能的,它只取决于你需要的东西。
您可以阅读特征类here的简短介绍。如果你想了解更多关于这个主题的信息,我建议你使用Modern C ++(Alexandrescu)。
答案 4 :(得分:0)
我不确定我完全明白你在问什么。序列化和反序列化的常用方法是创建工厂(抽象工厂)并动态解析对象的构造。请注意,这可以针对复杂结构进行改进,其中代码生成器可以创建成员函数以提取每个成员的确切类型。
但同样,我并不完全明白你真正要做的事情......作为一项建议我相信如果你提供更多关于要解决的问题的描述会有所帮助,因为问题集中于如何使您的解决方案有效,并隐含地放弃可能更好设计的其他方法。