问题
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;
}
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 ?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 usesizeof
?
回答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!
回答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.
回答3:
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;
回答4:
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)
来源:https://stackoverflow.com/questions/23895981/how-can-the-min-type-be-found-in-a-variadic-parameter-pack