如何模仿模板变量声明
Posted
技术标签:
【中文标题】如何模仿模板变量声明【英文标题】:How to mimic template variable declaration 【发布时间】:2014-01-04 22:19:46 【问题描述】:我有一个基本类型 Item<N>
,它依赖于一个整数模板参数 N
和类 Data
,它为几个不同的 N
保存 Item<N>
的实例。
这是一个例子:
template<unsigned N>
struct Item ... ; // some template data type
struct Data
std::set<Item<1>> items1;
std::set<Item<2>> items2;
std::set<Item<3>> items3;
std::set<Item<4>> items4;
std::set<Item<5>> items5;
bool contains(const Item<1>& x) return items1.find(x) != items1.end();
bool contains(const Item<2>& x) return items2.find(x) != items2.end();
bool contains(const Item<3>& x) return items3.find(x) != items3.end();
bool contains(const Item<4>& x) return items4.find(x) != items4.end();
bool contains(const Item<5>& x) return items5.find(x) != items5.end();
;
现在有几个函数,比如contains
,有很多代码重复。有没有更优雅的方式来实现Data
?
【问题讨论】:
可能是 N = [1..5] 范围内的某种递归定义?我仍然在这里尝试了解您的用例:N
与Data
的实例化规则相关的条件是什么?
导致您提出这个问题的设计选择似乎很糟糕。此代码不是自我记录的,因此存在维护风险。名称是编写现代可维护代码的重要组成部分——不要低估它们的价值。我建议寻找更优雅的设计。数字模板似乎不太适合项目。
@Mark:我正在寻找更优雅的设计,因此提出了问题;)
【参考方案1】:
例如,您可以存储一个合适的 std::tuple<...>
并将您的 contain()
函数作为模板,例如:
template <int... I>
struct DataImpl
std::tuple<std::set<Item<I>>...> data;
template <int J>
bool contains(Item<J> const& x)
return std::get<J-1>(data).find(x) != std::get<J-1>(data).end();
;
using Data = DataImpl<1, 2, 3, 4, 5>;
【讨论】:
这也适用于 DataImpl 吗? @Danvil:不,这会给你访问错误:序列不是重新排序的,元组中的位置是从推导的类型派生的。如果您想使用任意顺序,则需要对整数序列进行排序/填充,这可以完成但可能不是一个简单的练习。 @Danvil:不像写的那样,因为std::get<N>(data)
返回std::tuple
的第N个元素,在C++1y中,我们可以使用std::get<std::set<Item<J - 1>>>(data)
@Jarod42:好点。类似基于类型的函数get<...>()
也可以用 C++11 编写。我认为也不是很简单,但比对值进行排序更容易。
为了更容易你可以使用 C++1y std::integer_sequence
和 std::make_index_sequence
所以实例化看起来像 template<int N> using Data = DataImpl<std::make_index_sequence<N>>; template class Data<5>;
DataImpl
必须专门为 std::integer_sequence
而你会参数包中也要加一:tuple<set<Item<(Is + 1)...>>>
【参考方案2】:
以下可能会有所帮助:
struct Data
std::tuple<std::set<Item<1>>,
std::set<Item<2>>,
std::set<Item<3>>,
std::set<Item<4>>,
std::set<Item<5>>> items;
template <int N>
bool contains(const Item<N>& x) const
static_assert(0 < N && N < 6, "N out of range");
return std::get<N - 1>(items).find(x) != std::get<N - 1>(items).end();
;
【讨论】:
【参考方案3】:用“类型列表”来做点什么,像这样:
template <unsigned int ...> struct Data;
template <> struct Data<> ;
template <unsigned int N, unsigned int ...Tail>
struct Data : Data<Tail...>
std::set<Item<N>> item;
bool contains(const Item<N> & x) const return item.find(x) != item.end();
;
用法:
Data<2, 8, 19> data; // contains sets of Item<2>, Item<8> and Item<19>
【讨论】:
以上是关于如何模仿模板变量声明的主要内容,如果未能解决你的问题,请参考以下文章