How to create a static compilation type class that initializes a member container with specific values?

This is basically what I want:

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

No need to be deque , I just want to link the iterable list of values ​​with type . So that I can do something like

 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; } 

This usually makes things dynamic, which is a problem, but it seems just as difficult to do some dynamic things for compilation. I do not want to use inheritance, polymorphism, and similar runtimes, suggestive approaches.

+5
source share
2 answers

You cannot have a time list for compiling custom structures. And you cannot have std::string compilation time. It is not a type literal and therefore cannot be used in any constexpr context.

If you are limited to types that can be used in non-piggy template options , you can use a variation template type. And then you don't need to worry about the runtime container:

 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...>();} }; 

Living example .

However, it should be borne in mind that compilers have rather strict restrictions on the number of template parameters that a type can have. You probably won't miss this limit by typing them on the keyboard, but you can design them by.

+5
source

How about using Variable arguments without a pattern?

Sort of

--- edit: fixed (thanks ms) ---

--- edit2: added _items2 array ---

 #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; } 
+2
source

All Articles