如何创建一个初始化具有特定值的成员容器的编译时静态类类型?

时间:2016-06-18 13:59:22

标签: c++ templates c++11

这基本上就是我想要的:

struct Item{
   int id;
   std::string s;   
};

template <???>
struct StaticContainer
{
    static const std::deque<Item> _items;
};

template <???>
const std::deque<Item> StaticContainer<>::_items {???};

不必是deque,我只想将可迭代的值列表与type相关联。所以我可以做像

这样的事情
typedef StaticContainer<{{1, "a", {2, "b"}, {3, "c"}}> T1;
typedef StaticContainer<{{0, "e"}, {-1, "f"}, {-2, "g"}}> T2;

int main() {
   T1 t1;
   T2 t2;
   t1 = t2; // Error: incompatible types

   return 0;
}

通常它会让事情变得动态,这就是问题所在,但显然很难让一些动态的东西成为编译时间。 我不想使用继承,多态和类似的运行时,开销诱导方法。

2 个答案:

答案 0 :(得分:5)

您不能拥有用户定义的结构的编译时列表。而且你不能拥有任何类型的编译时std::string 。它不是literal type,因此无法在任何constexpr上下文中使用。

如果您将自己限制为可以在non-type template parameters中使用的类型,则可以使用可变参数模板类型。然后,您不必费心使用运行时容器:

template<typename T, T ...ts>
struct value_list
{
    //Not the most efficient way to get a value.
    template<int ix>
    static constexpr auto get()
    { return std::get<ix>(std::make_tuple(ts...)); }

    //Get a general container
    template<typename Container>
    static auto get_container() {return Container{ts...};}

    //Get an array, appropriately sized.
    static constexpr auto get_array()
    { return std::array<T, sizeof...(ts)>{ts...}; }

    //Manipulators. Types are static, so they must return
    //new types with the new values.
    template<T new_val>
    constexpr auto push_back()
    {return value_list<T, ts..., new_val>();}

    template<T new_val>
    constexpr auto push_front()
    {return value_list<T, new_val, ts...>();}
};

Live example

但是,请注意,编译器对类型可以具有的模板参数的数量有相当严格的限制。

,你可能不会在键盘上键入它们,但是你可能不会超过这个限制。

答案 1 :(得分:2)

使用可变参数模板非类型参数怎么样?

这样的东西

---编辑:更正(谢谢m.s.)---

--- edit2:添加了数组_items2 ---

#include <deque>
#include <array>
#include <iostream>

struct Item{
   int id;   
};

template <int ... vals>
struct StaticContainer
{
    static const std::deque<Item> _items;
    static const std::array<Item, sizeof...(vals)> _items2;
};

template <int ... vals>
const std::deque<Item> StaticContainer<vals...>::_items { {vals}... };

template <int ... vals>
const std::array<Item, sizeof...(vals)> StaticContainer<vals...>::_items2 { { {vals} ... } };

typedef StaticContainer<1, 2, 3> T1;
typedef StaticContainer<0, -1, -2> T2;

int main ()
 {
   T1 t1;
   T2 t2;
   //t1 = t2; // Error: incompatible types

   std::cout << T1::_items[1].id << std::endl;
   std::cout << T2::_items2[0].id << std::endl;

   return 0;
 }