如何模仿模板变量声明

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] 范围内的某种递归定义?我仍然在这里尝试了解您的用例:NData 的实例化规则相关的条件是什么? 导致您提出这个问题的设计选择似乎很糟糕。此代码不是自我记录的,因此存在维护风险。名称是编写现代可维护代码的重要组成部分——不要低估它们的价值。我建议寻找更优雅的设计。数字模板似乎不太适合项目。 @Mark:我正在寻找更优雅的设计,因此提出了问题;) 【参考方案1】:

例如,您可以存储一个合适的 std::tuple&lt;...&gt; 并将您的 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&lt;N&gt;(data)返回std::tuple的第N个元素,在C++1y中,我们可以使用std::get&lt;std::set&lt;Item&lt;J - 1&gt;&gt;&gt;(data) @Jarod42:好点。类似基于类型的函数get&lt;...&gt;() 也可以用 C++11 编写。我认为也不是很简单,但比对值进行排序更容易。 为了更容易你可以使用 C++1y std::integer_sequencestd::make_index_sequence 所以实例化看起来像 template&lt;int N&gt; using Data = DataImpl&lt;std::make_index_sequence&lt;N&gt;&gt;; template class Data&lt;5&gt;; DataImpl 必须专门为 std::integer_sequence 而你会参数包中也要加一:tuple&lt;set&lt;Item&lt;(Is + 1)...&gt;&gt;&gt;【参考方案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>

【讨论】:

以上是关于如何模仿模板变量声明的主要内容,如果未能解决你的问题,请参考以下文章

在 Play2 Scala 模板中声明变量

1如何声明一个类?如何创建类的对象?

如何使用模板声明成员函数? (不是模板类)

带有 std::map 的模板函数给出错误:声明为 void 的变量或字段

letconstvar模板字符串箭头函数

saltstack之jinja模板