Получение самого большого доступного типа - PullRequest
7 голосов
/ 19 июня 2011

Как я могу получить имя самого большого доступного типа в моем компиляторе?Это вообще возможно?
Что-то вроде:

auto largest = get_largest_type();  

, а авто в моем случае будет длинным.

Ответы [ 5 ]

4 голосов
/ 26 июня 2011

Ну, в зависимости от того, насколько сильно вам это нужно, вы можете попробовать серьезную метапрограммирование здесь ...

Во-первых, вам, очевидно, понадобится некая «пачка», определяющая все доступные типы примитивов, поэтому вот она:

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!
2 голосов
/ 19 июня 2011

Только для целочисленных типов, вы можете использовать заголовок <cstdint>, который позволяет вам:

std::intmax_t largest;

Я не знаю ни о какой такой функциональности, которая включает типы с плавающей запятой.

2 голосов
/ 19 июня 2011

Нет, это невозможно.Тем не менее, вы можете в значительной степени гарантировать, что 64-битный - самый большой тип - я не знаю ни одного компилятора, который предлагает 128-битный.В противном случае попросите пользователя передать его в качестве параметра шаблона или использовать специфичные для компилятора определения для определения типа.

1 голос
/ 19 июня 2011

Полагаю, вы могли бы написать небольшую программу, которая перерабатывает вашу основную программу. Маленькая программа может использовать sizeof () для сравнения всех числовых типов, чтобы определить самый большой. Затем замените символ «КРУПНЕЙШИЙ» в вашей основной программе на тип, который на самом деле был самым большим.

0 голосов
/ 19 июня 2011

Вы можете использовать шаблонный класс std :: numeric_limits , чтобы получить некоторую информацию о примитивных типах, имеющих специализации.

Обратите внимание, что на некоторых компиляторах long double большеlong long хотя для других long double - это размер double (MSVC).

...