Ну, в зависимости от того, насколько сильно вам это нужно, вы можете попробовать серьезную метапрограммирование здесь ...
Во-первых, вам, очевидно, понадобится некая «пачка», определяющая все доступные типы примитивов, поэтому вот она:
template<typename... TYPES>
class pack
{};
typedef pack<float, double, long double, unsigned short, unsigned int,
unsigned long, unsigned long long, short, int, long, long long> primitive_types;
Тогда вам понадобится способ сортировки этих типов по размеру, поэтому, во-первых, давайте определим метафункцию, способную реализовать строгий слабый порядок для размеров:
template<typename L, typename R>
class smaller
{
public:
static const bool value = sizeof(L) < sizeof(R);
};
Теперь алгоритм сортировки. Здесь я произвольно выбрал сортировку слиянием, для которой потребовалось 3 других метафункции: pack_cat
для объединения пакетов, pack_merge
для объединения их в соответствии с порядком и halve
для разбиения пакетов в 2 других пакетах.
template<typename, typename>
class pack_cat;
template<typename... L, typename... R>
class pack_cat<pack<L...>, pack<R...>>
{
public:
typedef pack<L..., R...> type;
};
template<template<typename, typename> class, typename, typename>
class pack_merge;
template<template<typename, typename> class MF, typename HL, typename... TL, typename HR, typename... TR>
class pack_merge<MF, pack<HL, TL...>, pack<HR, TR...>>
{
public:
typedef typename std::conditional<MF<HR, HL>::value,
typename pack_cat<pack<HR>, typename pack_merge<MF, pack<HL, TL...>, pack<TR...>>::type>::type,
typename pack_cat<pack<HL>, typename pack_merge<MF, pack<TL...>, pack<HR, TR...>>::type>::type>::type type;
};
template<template<typename, typename> class MF, typename H, typename... T>
class pack_merge<MF, pack<H, T...>, pack<>>
{
public:
typedef pack<H, T...> type;
};
template<template<typename, typename> class MF, typename... R>
class pack_merge<MF, pack<>, pack<R...>>
{
public:
typedef pack<R...> type;
};
template<typename>
class halve;
template<typename A, typename B, typename... T>
class halve<pack<A, B, T...>>
{
public:
typedef typename pack_cat<pack<A>, typename halve<pack<T...>>::L>::type L;
typedef typename pack_cat<pack<B>, typename halve<pack<T...>>::R>::type R;
};
template<typename T>
class halve<pack<T>>
{
public:
typedef pack<T> L;
typedef pack<> R;
};
template<>
class halve<pack<>>
{
public:
typedef pack<> L;
typedef pack<> R;
};
template<template<typename, typename> class MF, typename P>
class pack_sort
{
private:
typedef typename halve<P>::L L;
typedef typename halve<P>::R R;
public:
typedef typename pack_merge<MF, typename pack_sort<MF, L>::type, typename pack_sort<MF, R>::type>::type type;
};
template<template<typename, typename> class MF, typename H>
class pack_sort<MF, pack<H>>
{
public:
typedef pack<H> type;
};
template<template<typename, typename> class MF>
class pack_sort<MF, pack<>>
{
public:
typedef pack<> type;
};
Наконец, вам понадобится мета-функция для получения последнего аргумента пакета, которую легко реализовать:
template<typename>
class pack_get_last;
template<typename H, typename... T>
class pack_get_last<pack<H, T...>>
{
public:
typedef typename pack_get_last<pack<T...>>::type type;
};
template<typename H>
class pack_get_last<pack<H>>
{
public:
typedef H type;
};
Теперь тестовая программа, которая докажет вам, что весь этот ненужный код, который я там написал, действительно работает:
#include <iostream>
#include <utility>
/* all those metafunctions come here */
int main()
{
typename pack_get_last<typename pack_sort<smaller, primitive_types>::type>::type largest;
if(std::is_same<decltype(largest), long double>::value)
std::cout << "MATCH!\n";
}
Вывод на компьютере x64 Linux с использованием gcc 4.6, где long double - это самый большой доступный простой тип примитива:
MATCH!