如何在同一可变参数模板的不同实例之间进行转换?
How to convert between different instantiations of the same variadic template?
假设我们有一个数据结构 Foo 维护一组元素。应该可以根据需要将属性与元素相关联。每个属性都应该存储在一个单独的向量中。我们通过可变参数模板实现这一点:
#include <vector>
template <typename ...Attrs>
struct Foo : public Attrs... {
Foo(int n = 0) {
using PackExpansionT = int[];
PackExpansionT{0, (Attrs::values.resize(n), 0)...};
}
};
struct AttrA { std::vector<int> values; };
struct AttrB { std::vector<float> values; };
struct AttrC { std::vector<double> values; };
int main() {
Foo<AttrA, AttrB> foo; // Maintains set of elements with two attributes each.
};
现在,我想要一个具有以下语义的转换运算符:
Foo<AttrB, AttrC> bar = foo; // bar.AttrB::values should be a copy of foo.AttrB::values.
这只是一个例子。通常,转换运算符应该能够将具有任意属性的 Foo
转换为另一个具有任意属性的 Foo 。应复制与两个 Foo
关联的属性。与两者都没有关联的属性可以保留为默认值。但是,我不知道如何实现它。
template <typename ...OthersAttrs>
operator Foo<OthersAttrs...>() const {
// ...?
}
我能想到的提纲:
template <typename ...OthersAttrs>
operator Foo<OthersAttrs...>() const
{
Foo<OthersAttrs...> rv(GetNSomehow());
(int[]){(CopyAttr<Attrs>(&rv), 0)...};
return rv;
}
template<typename Attr>
void CopyAttr(Attr *rv) const // Overload A
{
rv->values = ((const Attr*)this)->values;
}
template<typename Attr>
void CopyAttr(...) const // Overload B
{
}
这里的技巧是逐个属性。
如果 rv
具有属性,将选择第一个重载并将其复制。
否则将选择不执行任何操作的第二个重载。
我们可以做出一堆独立的决定。首先,让我们添加一个构造函数,以便我们可以从其属性成分构造 Foo
:
Foo(Attrs const&... attrs)
: Attrs(attrs)...
{ }
接下来,对于 Others
中的每个属性,如果可能,我们将 this
向下转换为适当的类型,否则 return 默认构造的类型:
template <typename... Others>
operator Foo<Others...>() const {
return {get_attr<Others>(this)...};
}
其中:
template <class T>
T const& get_attr(T const* v) const {
return *v;
}
template <class T>
T get_attr(...) const {
return T{};
}
假设我们有一个数据结构 Foo 维护一组元素。应该可以根据需要将属性与元素相关联。每个属性都应该存储在一个单独的向量中。我们通过可变参数模板实现这一点:
#include <vector>
template <typename ...Attrs>
struct Foo : public Attrs... {
Foo(int n = 0) {
using PackExpansionT = int[];
PackExpansionT{0, (Attrs::values.resize(n), 0)...};
}
};
struct AttrA { std::vector<int> values; };
struct AttrB { std::vector<float> values; };
struct AttrC { std::vector<double> values; };
int main() {
Foo<AttrA, AttrB> foo; // Maintains set of elements with two attributes each.
};
现在,我想要一个具有以下语义的转换运算符:
Foo<AttrB, AttrC> bar = foo; // bar.AttrB::values should be a copy of foo.AttrB::values.
这只是一个例子。通常,转换运算符应该能够将具有任意属性的 Foo
转换为另一个具有任意属性的 Foo 。应复制与两个 Foo
关联的属性。与两者都没有关联的属性可以保留为默认值。但是,我不知道如何实现它。
template <typename ...OthersAttrs>
operator Foo<OthersAttrs...>() const {
// ...?
}
我能想到的提纲:
template <typename ...OthersAttrs>
operator Foo<OthersAttrs...>() const
{
Foo<OthersAttrs...> rv(GetNSomehow());
(int[]){(CopyAttr<Attrs>(&rv), 0)...};
return rv;
}
template<typename Attr>
void CopyAttr(Attr *rv) const // Overload A
{
rv->values = ((const Attr*)this)->values;
}
template<typename Attr>
void CopyAttr(...) const // Overload B
{
}
这里的技巧是逐个属性。
如果 rv
具有属性,将选择第一个重载并将其复制。
否则将选择不执行任何操作的第二个重载。
我们可以做出一堆独立的决定。首先,让我们添加一个构造函数,以便我们可以从其属性成分构造 Foo
:
Foo(Attrs const&... attrs)
: Attrs(attrs)...
{ }
接下来,对于 Others
中的每个属性,如果可能,我们将 this
向下转换为适当的类型,否则 return 默认构造的类型:
template <typename... Others>
operator Foo<Others...>() const {
return {get_attr<Others>(this)...};
}
其中:
template <class T>
T const& get_attr(T const* v) const {
return *v;
}
template <class T>
T get_attr(...) const {
return T{};
}