templates - Automatically incrementing an index in the following macro generated structs in C++ -
i have template function looks this:
template <class t> void foo(t* t) { //do stuff using: somearray[idx]; //idx depends on t }
there handful of possible types t
, approach in unnamed namespace:
struct sentinel; template <class t> struct offsets {}; #define genidx(t,num) template <> struct offsets<t> {static const int idx = num;}; genidx(fox, 0) genidx(cat, 1) genidx(rat, 2) genidx(sentinel, 3) static const size_t numtypes = offsets<sentinel>::idx;
and later on, member array somearray
declared somearray[numtypes];
and foo method implemented this:
template <class t> void foo(t* t) { typedef offsets<t> offset_t; somearray[offset_t::idx]; //idx depends on t }
and if needs add new type system, can add new genidx
, work. nuisance if wants add, say, wolf
mix, want logically appear before cat
have bump remaining indices manually. wondering if there way not require numerical indices in macro, , instead let automatically sequentially generated. this, except below doesn't work:
size_t numtypes = 0; template <class t> struct offsets {}; #define genidx(t) template <> struct offsets<t> {static const int idx = numtypes++;}; genidx(fox) genidx(cat) genidx(rat)
after numtypes
correctly contain size of array. not require index management when inserting new specializations anywhere in mix , interesting, if @ least curiosity point of view, know how done.
also though of doing this, after realized don't have __counter__
on gcc version:
template <class t> struct offsets {}; #define genidx(t) \ template <> struct offsets<t> \ { \ #include boost_pp_update_counter() \ static const int idx = counter; \ };
but above fails because can't #include
inside macro...
a c++11 solution
some includes , helper:
#include <cstddef> #include <tuple> #include <type_traits> #include <iostream> template < typename t0, typename t1 > constexpr auto c_min(t0 p0, t1 p1) -> typename std::common_type<t0, t1>::type { return p0 < p1 ? p0 : p1; }
your types , "collection" of types:
struct fox {}; struct cat {}; struct rat {}; using my_types = std::tuple < fox, cat, rat >;
two functions:
// returns size of collection constexpr std::size_t get_size() { return std::tuple_size<my_types>::value; } // `get_index < type > ();` returns index of type in collection // no definition required, used suppress error messages template < typename, std::size_t > constexpr std::size_t get_index(std::integral_constant<bool, true>); template < typename t, std::size_t t = 0 > constexpr std::size_t get_index(std::integral_constant<bool, false> = {}) { using current = typename std::tuple_element<t, my_types>::type; using issame = std::is_same<t, current>; static_assert(issame{} || t+1 < get_size(), "unknown type: passed type not in tuple."); using iserror = std::integral_constant< bool, (issame{} || t+1 == get_size()) >; return issame{} ? t : get_index<t, t+1>( iserror{} ); }
usage example:
int somearray[ get_size() ] = {0}; template < class t > void foo(t* t) { somearray[ get_index<t>() ] = 42; } int main() { std::cout << "array before modification: "; for(auto const& e : somearray) { std::cout << e << ", "; } std::cout << std::endl; struct cow {}; cow f; foo(&f); std::cout << "array after modification: "; for(auto const& e : somearray) { std::cout << e << ", "; } std::cout << std::endl; }
Comments
Post a Comment