【问题标题】: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:我正在寻找更优雅的设计,因此提出了问题;)

标签: c++ templates


【解决方案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>
    

    【讨论】:

      猜你喜欢
      • 2016-04-15
      • 2010-10-17
      • 1970-01-01
      • 2018-08-04
      • 2020-05-10
      • 2016-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多