fork(1) download
  1. #include <iostream>
  2. #include <type_traits>
  3.  
  4. //#define DONT_SUPPORT_DEFAULTS
  5.  
  6. template<class _B, template <class,class,_B> class... _Fs>
  7. class Flags
  8. {
  9. public:
  10. template<_B... _Vs>
  11. class WithValues : public _Fs<_B, Flags<_B,_Fs...>::WithValues<_Vs...>, _Vs>...
  12. {
  13. public:
  14. typedef _B base_type;
  15. template <base_type _V>
  16. inline constexpr explicit WithValues(std::integral_constant<base_type, _V>) : x(_V) { } // done in a strange way to allow the more natural constructor be non-constexpr
  17. inline explicit WithValues(base_type b) : x(b) { } // non-constexpr so I can add an exception to the body
  18.  
  19. // ... (implementation details unnecessary)
  20.  
  21. private: base_type x;
  22. };
  23. private:
  24. struct _F { template <_B _V> inline constexpr explicit _F(std::integral_constant<_B, _V>) { } }; // dummy class which can be given to a flag-name template
  25. static constexpr unsigned _count = sizeof...(_Fs<_B, _F, 1>); // we count the flags, but only in a dummy way
  26.  
  27. static inline constexpr _B pow2(unsigned exp, _B base = 2, _B result = 1) { return exp < 1 ? result : pow2(exp/2, base*base, (exp % 2) ? result*base : result); }
  28.  
  29. #ifndef DONT_SUPPORT_DEFAULTS
  30. template <_B... _Is> struct indices { using next = indices<_Is..., sizeof...(_Is)>; using WithPow2Values = WithValues<pow2(_Is)...>; };
  31. template <unsigned N> struct build_indices { using type = typename build_indices<N-1>::type::next; };
  32. template <> struct build_indices<0> { using type = indices<>; };
  33.  
  34. //// Another attempt
  35. //template < _B... _Is> struct indices { using WithPow2Values = WithValues<pow2(_Is)...>; };
  36. //template <unsigned N, _B... _Is> struct build_indices : build_indices<N-1, N-1, _Is...> { };
  37. //template < _B... _Is> struct build_indices<0, _Is...> : indices<_Is...> { };
  38.  
  39. public:
  40. using WithDefaultValues = typename build_indices<_count>::type::WithPow2Values;
  41. #endif
  42. };
  43.  
  44. template <class _B, class _F, _B _V> struct FLAG_A { static constexpr const _F A = _F(std::integral_constant<_B,_V>()); };
  45. template <class _B, class _F, _B _V> struct FLAG_B { static constexpr const _F B = _F(std::integral_constant<_B,_V>()); };
  46. template <class _B, class _F, _B _V> struct FLAG_C { static constexpr const _F C = _F(std::integral_constant<_B,_V>()); };
  47.  
  48. typedef Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>::WithValues<1, 2, 4> MyFlags;
  49. #ifndef DONT_SUPPORT_DEFAULTS
  50. typedef Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>::WithDefaultValues MyFlags2;
  51. #endif
  52.  
  53. int main()
  54. {
  55. std::cout << "Compiled and ran!" << std::endl;
  56. return 0;
  57. }
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.cpp:32:15: error: explicit specialization in non-namespace scope ‘class Flags<_B, _Fs>’
     template <>           struct build_indices<0> { using type = indices<>; };
               ^
prog.cpp:32:34: error: template parameters not used in partial specialization:
     template <>           struct build_indices<0> { using type = indices<>; };
                                  ^
prog.cpp:32:34: error:         ‘_B’
prog.cpp:32:34: error:         ‘template<class, class, _B <anonymous> > class ... _Fs’
prog.cpp:31:105: error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) instantiating ‘struct Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>::build_indices<4294966400u>’
     template <unsigned N> struct build_indices    { using type = typename build_indices<N-1>::type::next; };
                                                                                                         ^
prog.cpp:31:105:   recursively required from ‘struct Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>::build_indices<2u>’
prog.cpp:31:105:   required from ‘struct Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>::build_indices<3u>’
prog.cpp:40:83:   required from ‘class Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>’
prog.cpp:48:53:   required from here

prog.cpp:31:105: error: invalid use of incomplete type ‘struct Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>::build_indices<4294966400u>’
prog.cpp:31:34: error: declaration of ‘struct Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>::build_indices<4294966400u>’
     template <unsigned N> struct build_indices    { using type = typename build_indices<N-1>::type::next; };
                                  ^
stdout
Standard output is empty