2

By "min" type, I mean the type compared less than all according to a compile time function, eg sizeof

I have a draft implementation, will present it first and refer to the two problems I'm facing:

#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;
}
  1. This does not work in VS2013 (emits fatal error C1075). Am I using any non standard facilities or is there a more conforming way to write the above ?

  2. Say I want to use means other than sizeof to compare types. Is there a consice way / good design to be able to pass metafunctions as comparators and still maintain a default behaviour (where non specified otherwise that is) that would use sizeof ?

Constructor
  • 7,273
  • 2
  • 24
  • 66
Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • You don't usually use `sizeof` to compare types ... – Chnossos May 27 '14 at 18:04
  • @Chnossos Yes, the ordering may vary across implementations. That's why in (2) I ask for a way to pass custom metafunctions to perform the comparison (it would be good to have a default comparator, much like `<` for the STL runtime counterparts). This is a follow up of [this](http://stackoverflow.com/q/23815138/2567683), designs therein may help in any answers – Nikos Athanasiou May 27 '14 at 18:07

4 Answers4

2

Looks like MSVC is screwing up parsing the std::conditional expression. It seems to think the less than between sizeof(T1) < sizeof(T2) is the opening < of another template argument. 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 an MSVC bug to me.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
1

If you want to use different predicates, the following 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;
}

Live example

Note that you need to be careful with how you recurse. Example for four type and your version might yield all of the following instantiations:

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 only yields four instantiations total. The more arguments you add, the more important this becomes!

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
1

Following works with 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 a default behavior, you have to change the prototype to something like

template <typename Tuple, template <typename, typename> class Less = DefaultLess>
struct Tmin;
Jarod42
  • 203,559
  • 14
  • 181
  • 302
1

First, as Praetorian said, the not-compiling is certainly a MSVC bug. It works perfectly, even without the parenthesis, in g++ and clang++.

Second, you can wrap your Tmin in another template (I called it TTmin, yeah, really original) and you may use any comparison class 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)

Massa
  • 8,647
  • 2
  • 25
  • 26
  • Oh, I like the wrapper idea. Otherwise very similar to what I wrote. http://coliru.stacked-crooked.com/a/929535c1a29aeab7 – Mooing Duck May 27 '14 at 18:30