Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Вычисление максимального числа в массиве на этапе компиляции

Anna | 24.06.2014 | нет комментариев

Не так давным-давно потребовалось вычислить максимальную длину из нескольких заданных строк на этапе компиляции. Необходимо выделить память под массив char[], так Дабы в нем уместилась любая строка из заданных. Разумно предположить, что если система спроектирована отлично, никаких вычислений на этапе компиляции не необходимо, дозволено воспользоваться динамическим выделением применяя std::auto_ptr либо std::string, но это не тот случай. Конструкция в которой хранится буфер char[] должна быть POD-типом.

По сути задача сводится к определению максимального числа в массиве на этапе компиляции. В данном топике я покажу как это сделать в эталоне c 03 и c 11. В ходе поиска решений обнаружил две статьи, которые помогли мне решить задачу: habrahabr.ru/post/166201/habrahabr.ru/post/38622/.

Выходит, Дабы обойти все заданные строки, сложим их в массив:

const char str1[] = "Anna";
const char str2[] = "Denis";
const char str3[] = "Vladimir";
const char str4[] = "Alexey";

const char *arr[] = { str1, str2, str3, str4 };

Сейчас, sizeof(arr) вернет 16, а sizeof(arr[2]) вернет 4. Увы, мы утратили информацию о размере строк в всяком элементе массива arr. Трюк с тем Дабы положить итоги sizeof всякой строки в массив тоже не прокатит, так как на этапе компиляции не разрешены операции разыменовывания указателей. Вообщем необходимо искать что-то помощнее обыкновенных массивов…
Решение данной задачи – это сделать эмуляцию массива с поддержкой конструкций. Сложим длины всех строк в отдельные конструкции и свяжем их с поддержкой Loki::TypeList.

struct str_1 { static const int size = sizeof(str1); };
struct str_2 { static const int size = sizeof(str2); };
struct str_3 { static const int size = sizeof(str3); };
struct str_4 { static const int size = sizeof(str4); };

typedef LOKI_TYPELIST_4(str_1, str_2, str_3, str_4) List;      

Сейчас мы можем обойти данный список типов и у всякого из них выдернуть размер.

Итоговый вариант с 03

struct str_1 { static const int size = sizeof(str1); };
struct str_2 { static const int size = sizeof(str2); };
struct str_3 { static const int size = sizeof(str3); };
struct str_4 { static const int size = sizeof(str4); };

typedef LOKI_TYPELIST_4(str_1, str_2, str_3, str_4) List;       

#define GetMaxLen(TypeList) 

template<class Cur_Type> 
struct len               
{                        
    static const int cur_size = Cur_Type::Head::size;                                   
    static const int next_size = len<Cur_Type::Tail>::max_size;                         
    static const int max_size = cur_size > next_size ? cur_size : next_size ;           
};                                                                                      

template<>                                                                              
struct len<NullType>                                                                    
{                                                                                       
    static const int max_size = 0;                                                      
};                                                                                      

static const int ml = len<TypeList>::max_size;                                          

GetMaxLen(List);

// в *.cpp
// LOKI_STATIC_CHECK((ml == sizeof(str3)), size_is_wrong);

Данный вариант не самый комфортный, так как такую конструкцию легко поддерживать при касательно маленьком числе строк. Впрочем с увеличением данного числа существует вероятность легко позабыть добавить соответствующую конструкцию для строки.
На эталоне c 11 получается все гораздо прекраснее и комфортнее. Плюс не необходимо «извращаться» со конструкциями и списками типов. Нам разрешено разыменовывать указатели, но только constexpr и внутри constexpr функции.

Итоговый вариант с 11

constexpr const char str1[] = "Anna";
constexpr const char str2[] = "Denis";
constexpr const char str3[] = "Vladimir";
constexpr const char str4[] = "Alexey";

constexpr const char *arr[] = { str1, str2, str3, str4 };

#define GetMaxLenght(array) 
constexpr unsigned char str_len(const char* const str) 
{
   return *str ? (1   str_len(str   1)) : 0;
}

template <int index> 
struct MaxLenght
{
    static const int prev_size = MaxLenght<index-1>::max_size;
    static const int cur_size = str_len(array[index]);
    static const int max_size = cur_size > prev_size ? cur_size : prev_size;
};

template <>
struct MaxLenght<-1>
{
    static const int max_size = 0;
};
static const int AmountStr = sizeof(array) / sizeof(array[0]);
static const int array##_max_size = MaxLenght<AmountStr-1>::max_size;
GetMaxLenght(arr);

//   в *.cpp
//   static_assert((arr_max_size == 8), "Error");

P.S. Верю данная статья кому-то поможет.
P.P.S. Буду рад, если кто-то предложит решение с поддержкой boost либо еще каких-либо инструментов.

 

Источник: programmingmaster.ru

 

Оставить комментарий
БАЗА ЗНАНИЙ
СЛУЧАЙНАЯ СТАТЬЯ
СЛУЧАЙНЫЙ БЛОГ
СЛУЧАЙНЫЙ МОД
СЛУЧАЙНЫЙ СКИН
НОВЫЕ МОДЫ
НОВЫЕ СКИНЫ
НАКОПЛЕННЫЙ ОПЫТ
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB