C++, Сложные вычисления на этапе компиляции

capxaH

Как известно компилятор умеет сам вычислять длину константной строки, т.е. такой код отлично скомпилится

char str[] = "mamamylaramy";
const int size = sizeof(str)/sizeof(str[0]);
int array[size];

А можно ли на этапе компиляции посчитать количество различных букв в строке?

Papazyan

На Лиспе можно.

vall

Однажды я написал пачку макросов которые компилируются пару минут и требуют десять гигабайт памяти при этом. Этот кода кусок до сих пор там торчит и радует при каждой сборке. Оно тебе надо? Лучше написать отдельный кусок кода который будет исполняться на компиляции и генерировать то что нужно.

istran

Можно. С появлением constexpr в С++11, такие вещи стало делать намного проще. Например вот так:

#include <iostream>
#include <array>

constexpr size_t ndc_helper(const char* str, const size_t length, size_t pos,
std::array<bool, 256> seen_chars) {
return pos != 0) ? (seen_chars[(unsigned char)str[pos - 1]] = true) : true
(pos < length
? (!seen_chars[(unsigned char)str[pos]] +
ndc_helper(str, length, pos + 1, seen_chars
: 0;
}

template <size_t L>
constexpr size_t ndc(char (&str)[L]) {
return (L == 1) ? 0 : ndc_helper(str, L - 1, 0, std::array<bool, 256>
}

int main {
char str[] = "abcdefgabcdefggfedcba";
std::cout << ndc(str) << std::endl;
}

Но можно сделать то же самое и в C++98, используя рекурсивное инстанцирование шаблонов.
Если мне изменяет память, Александреску помимо списков типов, делал еще и множества.
UPD: переписал код немного. В первой версии было UB.

karkar

Можно сгенерить:
http://gergo.erdi.hu/projects/metafun/
А можно взять D:
int uniqueChars(string s) 
{
bool[char] chars;
foreach(c; s) chars[c] = true;
return chars.values.length;
}

void main(string[] argv)
{
static int n = uniqueChars("mamamylaramy");
writeln(n);
}

Тут static заставляет вычислить функцию при компиляции.

PITACHOK

Я бы с удовольствием взглянул на то, как это можно сделать в C++98, ибо, насколько я помню, в C++98 со строками на этапе компиляции могут работать только препроцессорные операторы # и ##, чего для данной задачи совершенно недостаточно.

Serpent555

Можно в С++98 с небольшим читом. Сделать рекурсивные шаблоны по длине строки, тогда в релизе эти вычисления оптимизируются и выполнятся на этапе компиляции (зависит от компилятора, конечно).
Удивительно, но это может быть полезно. Я так считал compile-time hash от имён исходных файлов, чтобы они не попали в релизный скомпилированный код (типа obscurity).

istran

Действительно, по-нормальному никак этого не сделать.
В boost-е, например, практикуют всякие извращения:

typedef mpl::string<'hell','o wo','rld'> hello;
typedef mpl::push_back<hello, mpl::char_<'!'> >::type hello2;

BOOST_ASSERT(0 == std::strcmp(mpl::c_str<hello2>::value, "hello world!";

http://www.boost.org/doc/libs/1_52_0/boost/mpl/string.hpp

okis

На нем, кстати, писали fizz buzz
Оставить комментарий
Имя или ник:
Комментарий: