How can I find the type "min" in a package of variable parameters?

By type "min" I mean a type that is compared less than everything according to a compile-time function, for example sizeof

I have a draft project that will be presented first, and consider two problems that I encounter:

 #include <iostream> #include <typeinfo> #include <type_traits> using namespace std; // Unspecialized version template<typename...Ts> struct Tmin { using type = void; }; template<typename T> struct Tmin<T> { using type = T; }; template<typename T1, typename T2, typename...Ts> struct Tmin<T1, T2, Ts...> { using type = typename std::conditional<sizeof(T1) < sizeof(T2), typename Tmin<T1, Ts...>::type, typename Tmin<T2, Ts...>::type >::type; }; int main() { cout << typeid(Tmin<float, int, double>::type).name() << endl; return 0; } 
  • This does not work in VS2013 (emits fatal error C1075 ). Am I using any non-standard means or is there a more suitable way to write above?

  • Say I want to use methods other than sizeof to compare types. Is there a way / good design to pass metafiles as comparators and support the default behavior (unless otherwise specified) that sizeof would use?

+2
c ++ c ++ 11 templates template-meta-programming variadic-templates
May 27 '14 at 17:58
source share
4 answers

If you want to use different predicates, you should work:

 #include <type_traits> #include <typeinfo> #include <iostream> template<template<typename,typename> class P, typename... Ts> struct min_t_impl; template<template<typename,typename> class P, typename T> struct min_t_impl< P, T > { using type = T; }; template<template<typename,typename> class P, typename T, typename U, typename... Ts> struct min_t_impl< P, T, U, Ts... > { using V = typename std::conditional< P<T,U>::value, T, U >::type; using type = typename min_t_impl< P, V, Ts... >::type; }; template<template<typename,typename> class P, typename... Ts> using min_t = typename min_t_impl<P,Ts...>::type; template<typename T,typename U> using my_pred = std::integral_constant< bool, ( sizeof(T) <= sizeof(U) ) >; int main() { std::cout << typeid(min_t<my_pred, float, int, double>).name() << std::endl; return 0; } 

Living example

Note that you need to be careful with how which you recurs. An example for four types, and your version may contain all of the following instances:

 Tmin<A,B,C,D> Tmin<A,C,D> Tmin<B,C,D> Tmin<A,D> Tmin<C,D> Tmin<B,D> Tmin<A> Tmin<B> Tmin<C> Tmin<D> 

while mine is linear and gives only four sums of copies. The more arguments you add, the more important it becomes!

+1
May 27 '14 at 18:27
source share

It looks like MSVC is parsing the std::conditional expression. It seems that less than between sizeof(T1) < sizeof(T2) is opening < another argument to the template. Add an extra set of parentheses and it works.

 template<typename T1, typename T2, typename...Ts> struct Tmin<T1, T2, Ts...> { using type = typename std::conditional<(sizeof(T1) < sizeof(T2)), // ^ ^ typename Tmin<T1, Ts...>::type, typename Tmin<T2, Ts...>::type >::type; }; 

Looks like MSVC error for me.

+2
May 27 '14 at 18:19
source share

After working with the visual:

 #include <iostream> #include <typeinfo> #include <type_traits> // Unspecialized version template <template <typename, typename> class Less, typename ... Ts> struct Tmin; template<template <typename, typename> class Less> struct Tmin<Less> { using type = void; }; template<template <typename, typename> class Less, typename T> struct Tmin<Less, T> { using type = T; }; template<template <typename, typename> class Less, typename T1, typename T2, typename...Ts> struct Tmin<Less, T1, T2, Ts...> { private: using lower_type = typename std::conditional<Less<T1, T2>::value, T1, T2>::type; public: using type = typename Tmin<Less, lower_type, Ts...>::type; }; template <typename T1, typename T2> struct sizeofLess : std::integral_constant<bool, (sizeof(T1) < sizeof (T2))> {}; int main() { std::cout << typeid(Tmin<sizeofLess, float, int, double>::type).name() << std::endl; return 0; } 

To have default behavior you need to change the prototype to something like

 template <typename Tuple, template <typename, typename> class Less = DefaultLess> struct Tmin; 
+1
May 27 '14 at 18:27
source share

First, as Praetorian said, non-compilation is certainly an MSVC bug. It works great, even without parentheses, in g ++ and clang ++.

Secondly, you can wrap Tmin in another template (I called it TTmin , yes, really original), and you can use any comparison class that you need:

 #include <iostream> #include <typeinfo> #include <type_traits> using namespace std; template<typename T1, typename T2> struct Tsmaller : std::integral_constant<bool, sizeof(T1) < sizeof(T2)> { }; template<template<typename, typename> class Compare = Tsmaller> struct TTMin { // Unspecialized version template<typename...Ts> struct Tmin { using type = void; }; template<typename T> struct Tmin<T> { using type = T; }; template<typename T1, typename T2, typename...Ts> struct Tmin<T1, T2, Ts...> { using type = typename std::conditional<Compare<T1, T2>::value, typename Tmin<T1, Ts...>::type, typename Tmin<T2, Ts...>::type >::type; }; }; int main() { cout << typeid(TTMin<>::Tmin<float, int, double>::type).name() << endl; return 0; } 

( link to live-at-coliru example )

+1
May 27 '14 at 18:29
source share



All Articles