c++11 - C++ How to make an std::tuple type based on partial specializations? -
i have template integer parameter, base template disabled static_assert() this. (i want specialization forms; want argument passed template prohibited except arguments)
template<itemid item_id> struct itemtemplate{ static_assert(item_id == -1,"cann't use unspecialized itemtemplate!"); static itemid id{ std::numeric_limits<itemid>::max() }; //... }; i have several specializations form template (i add or delete of them)
template<> struct itemtemplate<1>{ static constexpr itemid id{1}; //.. }; template<> struct itemtemplate<2>{ static constexpr itemid id{2}; //... }; now want create std::tuple initialised available types. in above example, itemtemplate<1> , itemtemplate<2>, not itemtemplate<3> , other non-specialized types. how achieve this?
i see way if forget static_assert() denial way , define only specializations of itemtemplate.
the following simplified example define specializations of foo , foo generic struct remain undefined.
template <std::size_t> struct foo; template <> struct foo<2u> {}; template <> struct foo<3u> {}; template <> struct foo<5u> {}; template <> struct foo<7u> {}; now need detect if type defined or not; example, following
template <typename t, std::size_t = sizeof(t)> std::true_type existh (int); template <typename> std::false_type existh (long); template <typename t> using exist = decltype(existh<t>(0)); that is: exist<foo<0>>::value false , exist<foo<2>>::value true.
now need list (usable compile time) of indexes of foo specialization defined lower limit (zero, example) upper limit.
you can obtain with
template <std::size_t i, std::size_t topi, typename, bool = (i == topi) || exist<foo<i>>::value> struct fooindexlist; template <std::size_t topi, std::size_t ... ixs> struct fooindexlist<topi, topi, std::index_sequence<ixs...>, true> { using type = std::index_sequence<ixs...>; }; template <std::size_t i, std::size_t topi, std::size_t ... ixs> struct fooindexlist<i, topi, std::index_sequence<ixs...>, true> { using type = typename fooindexlist<i+1u, topi, std::index_sequence<ixs..., i>>::type; }; template <std::size_t i, std::size_t topi, std::size_t ... ixs> struct fooindexlist<i, topi, std::index_sequence<ixs...>, false> { using type = typename fooindexlist<i+1u, topi, std::index_sequence<ixs...>>::type; }; using fooindexlist, obtaining std::tuple foo defined (from 0 upper limit) simple:
template <std::size_t ... idx> constexpr auto makefootupleh (std::index_sequence<idx...> const &) { return std::make_tuple( foo<idx>{} ... ); } constexpr auto makefootuple () { return makefootupleh( typename fooindexlist<0u, 100u, std::index_sequence<>>::type {}); } in example upper limit 100 can template parameter of makefootuple().
the following full compiling example
#include <tuple> #include <utility> #include <iostream> #include <type_traits> template <typename t, std::size_t = sizeof(t)> std::true_type existh (int); template <typename> std::false_type existh (long); template <typename t> using exist = decltype(existh<t>(0)); template <std::size_t> struct foo; template <> struct foo<2u> {}; template <> struct foo<3u> {}; template <> struct foo<5u> {}; template <> struct foo<7u> {}; template <std::size_t i, std::size_t topi, typename, bool = (i == topi) || exist<foo<i>>::value> struct fooindexlist; template <std::size_t topi, std::size_t ... ixs> struct fooindexlist<topi, topi, std::index_sequence<ixs...>, true> { using type = std::index_sequence<ixs...>; }; template <std::size_t i, std::size_t topi, std::size_t ... ixs> struct fooindexlist<i, topi, std::index_sequence<ixs...>, true> { using type = typename fooindexlist<i+1u, topi, std::index_sequence<ixs..., i>>::type; }; template <std::size_t i, std::size_t topi, std::size_t ... ixs> struct fooindexlist<i, topi, std::index_sequence<ixs...>, false> { using type = typename fooindexlist<i+1u, topi, std::index_sequence<ixs...>>::type; }; template <std::size_t ... idx> constexpr auto makefootupleh (std::index_sequence<idx...> const &) { return std::make_tuple( foo<idx>{} ... ); } constexpr auto makefootuple () { return makefootupleh( typename fooindexlist<0u, 100u, std::index_sequence<>>::type {}); } int main () { auto ft = makefootuple(); static_assert( std::is_same<decltype(ft), std::tuple<foo<2u>, foo<3u>, foo<5u>, foo<7u>>>{}, "!"); } limits:
- this solution works if generic
fooisn't defined - the code c++14; if need in c++11 it's little more complicated
- the upper limit in
makefootuple()can't big number becausefooindexlistrecursive limited compiler's recursion limit; can bypass limit require mode code.
Comments
Post a Comment