Monday, December 28, 2009

Итоги 2009 года

Хочу подвести итоги своего 2009 года.

1. Я женился.
2. На работе успел поучаствовать в 3х разных проектах. Первый проект был связан с travel-индустрией. Занимались реализацией новой версии системы автоматизации тур-оператора. Неплохо изучил .NET и T-SQL, хотя из-за того, что приходилось писать на VB .NET, не дотерпел до конца. Второй проект был посвящен написанию софта для промышленного портативного компьютера. Познакомился с Linux, Eclipse, g++ и Qt. Жалко, что моя работа закончилась через 3 недели, т.к. задача была конечная. Третий проект - это продукт "связанный с безопасностью" под Windows. Здоровенный монстр, состоящий из огромного количества унаследованного кода и заклинаний. Прокачал навыки удалённой отладки, познакомился с Active Directory и фиксом багов с формулировкой "не работает". Попадись мне этот проект лет 5 назад, наверное был бы счастлив.
3. Попробовал себя в фрилансе. Сделал девочке курсовую - чат на .NET Remoting. Заработал 200 баксов :-)
4. Windows и виртуалка с Linux превратились в Linux и виртуалку с Windows.
5. Немного ознакомился с GTK, GTK++ и ALSA.
6. Прочитал несколько книг о Python. Можно сказать - начал изучать. Сделал несколько hello world'ов. Познакомился с PyQt и PyOpenGl.
7. Начал изучать C++. Прочитал несколько книг. Познакомился с Boost и граблями C++. Понял не менее 50% книги А.Александреску "Современное проектирование на C++".
8. Немного поковырял микроконтроллер ATMEGA32. Сделал несколько лабораторных работ в симуляторе, научился мигать диодиками и делать прошивки.
9. Познакомился с Java. Прочитал несколько книг. Написал несколько hello world'ов для своего мобильного телефона Series 40. Понял, что немного опоздал с этим начинанием и это занятие уже малоактуально.
10. Сильно продвинулся с мечтой всей своей юности - собственной реализацией транслятора языка программирования. Во-первых разобрался с разбором текста (неплохо изучил Spirit Classic и написал собственную реализацию с аналогичной функциональностью), во-вторых сделал простенький язык программирования без системы типов, но с циклами, условиями и операторами.
12. Прочитал несколько книг по проектированию ПО. Пока мало что понятно, буду перечитывать.
13. Понял, что мне нужен велосипед и купил его.

На этом год кончился.

Thursday, December 24, 2009

Велосипед

Во вторник ко мне наконец-то приехал специализированный велосипед для фитнеса.

Вчера настроил, сегодня проверил. Я никогда не катался на сликах. Я бы, наверное, без особого энтузиазма стал кататься на них летом, а сейчас - зима. Ехать на работу было весело и непривычно. Узкий руль, мягкая вилка... и слики! Удивительно, но доехал. А вот домой ехать было сложнее. К вечеру стало теплее и пошёл дождь. Несколько раз я очень забавно скользил. Но всё-таки тоже доехал.

Не понять моей радости тем, у кого никогда не было велосипеда. Кто не знает, что это такое - ехать на велосипеде. Полтора года назад я очень сильно облажался купив триальный сток, на котором сиденье только в качестве украшения. Мне пришлось переставить часть деталей со своего старого велосипеда на этот новый. В результате получилось так, что старый велосипед исчез. От него осталась только рама и детали, а я стал обладателем непойми чего, на чём больше километра проехать - это подвиг.

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

J2ME Linux

Чтобы как-то отвлечься от всякого поднадоевшего, решил сегодня разобраться, как писать программки для моего мобильного телефона из-под линукса. Дело в том, что около полугода назад, когда ещё я сидел под Windows, написал несколько хеллоу-ворлдов для J2ME, чтобы хоть как-то оправдать наличие Java у меня в телефоне. С тех пор, как перешёл на линукс, меня мучает желание попробовать проделать то же самое под линуксом. Сегодня проверил. Да, действительно, это возможно.

Синтез современной музыки

Я периодически читаю блог А.Левенчука. 90% непонятно, остальные 10% - интересно. Сегодня наткнулся на пост Современная музыка: как она собирается. Выложено 10-минутное видео в котором некий DJ с нуля делает "Smack My Bitch Up". Самое интересное - показаны первоисточники используемых звуков.
Я удивлён.

Wednesday, December 23, 2009

Brainbench

Есть такой сайт - Brainbench. Этот сайт посвящен тестированию. Тестов на сайте очень много, но, в основном, самые интересные из них - платные. Периодически случается, что Brainbench решает временно сделать несколько тестов бесплатными. Сегодня пришло письмо, что среди прочих есть бесплатный тест "C++ Fundamentals". Конечно же решил пройти, результат такой:
Test:    C++ Fundamentals
Date: 23-Dec-2009
Score: 4.44
Weights: 100% C++ Fundamentals
Elapsed time: 35 min 34 sec
C++ Fundamentals
Score: 4.44
Percentile: Scored higher than 93% of previous examinees

Demonstrates a clear understanding of many advanced concepts within this
topic. Appears capable of mentoring others on most projects in this area.

Strong Areas
* Data Handling
* Flow Control
* Functions
* Exception Handling
* Building C++ Programs
* Templates

Weak Areas
* None noted

В прошлый раз этот тест я проходил в марте, набрал тогда 4.23 и осознал, что совершенно не знаю шаблоны. В этот раз в Weak Areas пусто.

Wednesday, December 16, 2009

Современный велосипед


Я, было, подумал, что книга - об антипаттернах.

Wednesday, November 25, 2009

Анонс

Последние полгода я занимался изучением того, что принято называть "Modern C++" изучая код Boost.Spirit (Classic). Фактически, то чем я занимался можно разделить на 2 части:
1. Изучение функциональности и основных идей Spirit.
2. Реализация своего варианта.

Особенно интересен второй пункт. Он состоит из двух подпунктов:
а. Язык C++ во всём своём великолепии. Можно охарактеризовать так: шаблонное метапрограммирование.
б. Проектирование и принятие решений.

Работа, в основном, состояла в (преднамеренных) бессчётных попытках изобрести велосипед. Я заставлял себя принимать аргументированные Решения. Я пытался слушать свою интуицию в надежде сделать лучше, чем оригинал Джоела Де Гузмана. Уходили недели на то, чтобы убедиться, что мои решения заводят весь проект в тупик и ничего с этим не сделаешь.
Кроме того, что за время работы мне удалось неплохо улучшить свои знания в C++, также удалось скорректировать своё понимание того, как нужно писать код и как его писать не нужно.

Надеюсь закончить полное описание этой работы через пару месяцев.

Monday, November 23, 2009

Тизер.


Фибоначчи:
a = b = 1;
i = 0;
while(i < 10) {
c = a + b;
?(c);
a = b;
b = c;
i = i + 1;
}

Результат:
PRINT: 2
PRINT: 3
PRINT: 5
PRINT: 8
PRINT: 13
PRINT: 21
PRINT: 34
PRINT: 55
PRINT: 89
PRINT: 144
CONTEXT:
'a' is 89
'b' is 144
'c' is 144
'i' is 10

P.S. Вот и кончился отпуск.

Thursday, November 19, 2009

3*(2+1)

Один из нескольких способов вычислить 3*(2+1) на C++.

#include <iostream>

//
struct empty_t {};

template<class Value, class Children = empty_t>
struct Node
{
typedef Value value;
typedef Children children;
};

template<class TA, class TB = empty_t>
struct Tree
{
typedef TA ta;
typedef TB tb;
};
//

//
struct Add
{
template<int A, int B>
struct Do { enum { value = A + B }; };
};

struct Mul
{
template<int A, int B>
struct Do { enum { value = A * B }; };
};

template<int X>
struct Val
{
enum { val = X };
};
//

//
template<class NodeT>
struct compute;

// если узел - это число
template<class ValueT>
struct compute<Node<ValueT, empty_t> >
{
enum { value = ValueT::val };
};

// если узел - это операция
template<class ValueT, class ChildrenT>
struct compute<Node<ValueT, ChildrenT> >
{
enum
{
A = compute<typename ChildrenT::ta>::value,
B = compute<typename ChildrenT::tb>::value,
value = ValueT::template Do<A, B>::value
};
};

int main()
{
// 3*(2+1)
typedef Node<
Mul,
Tree<
Node<Val<3> >,
Node<
Add,
Tree<
Node<Val<2> >,
Node<Val<1> >
>
>
>
> expr;

std::cout << compute<expr>::value << std::endl; // 9
}

По-моему, неплохой способ свести кого-нибудь с ума. Вообще не об этом. О том, что с помощью шаблонов можно забавно описывать статические древовидные структуры.

Saturday, November 7, 2009

Тизер.


...
int main()
{
char const* str = "myvalue=2*(yourvalue=1);myvalue=myvalue+1;";

typedef AstParseInfo<char const*> parse_info_t;
parse_info_t tpi =
ast_parse(str, str+strlen(str), MyGrammar(), *ch_p(' '));

typedef std::map<std::string, int> context_t;
context_t context;
int v = evaluate(tpi.nodes[0], context);

std::cout << "CONTEXT: " << std::endl;
typedef context_t::const_iterator context_iter_t;
for(context_iter_t it = context.begin(); it != context.end(); ++it)
{
std::cout
<< " '"
<< (*it).first
<< "' is "
<< (*it).second
<< std::endl;
}
}
...


debug: set 'yourvalue' to 1
debug: set 'myvalue' to 2
debug: set 'myvalue' to 3
CONTEXT:
'myvalue' is 3
'yourvalue' is 1
Press [Enter] to close the terminal ...

P.S. Наконец-то отпуск.

Saturday, October 31, 2009

C++0x

Свершилось. Наконец-то можно писать вот так:

#include <iostream>
#include <vector>

int main()
{
std::vector<int> v = {1, 2, 3};
for(auto it = v.begin(); it != v.end(); ++it)
std::cout << *it << std::endl;
}


Что забавно - скачал пару дней назад Visual Studio 2010 Beta 2, похоже, что в плане соответствия C++0x она ничем не отличается от первой беты. А вот g++ порадовал.

Ubuntu 9.10

Проапдейтилась убунта до 9.10.
1. g++ 4.4 в репозитории.
2. теперь не нужно ковыряться с .asoundrc чтобы сделать себе 5.1

Monday, October 26, 2009

Linux

Некоторое время назад я решил посмотреть на Windows 7. И пришёл к выводу, что я не хочу ЭТО использовать, хотя судя по всем прогнозам народ, который сейчас под XP будет на ЭТО переходить. Пусть переходят. А я перешёл на линукс.

На линукс я переходил уже очень много раз. И вот несколько месяцев назад я сделал это снова. В этот раз, скорее всего, под линуксом я и останусь. Windows вполне хватает на работе.

Вопреки всему моему горькому опыту ubuntu 9.04 отличнейшим образом определило всё железо на моём буке и без лишнего геморроя позволила одновременно использовать на буке и его собественный дисплей и внешний монитор, при это "аппаратное ускорение" работает нормально. В прошлый раз, на 8.04, мне не удалось этого добиться.

По поводу аналогов программ и юзабилити возникла всего 1 проблема: у линуксе всё как-то очень туго и геморройно со звуком. Вроде, да, ALSA, вроде, да, нет у них такого понятия как ASIO, но... сколько времени я должен на это потратить, чтобы у меня была возможность бренчать на гитаре? Пока такого времени у меня нет. Жаль.

Всё остальное работает отлично. Музыку можно слушать, по интернету можно лазить, аська опять же... Студии, конечно, нет. Для C++ использую NetBeans. Вместо .NET есть Mono, тут в качестве студии Mono Develop. И оно всё довольно-таки работает.

microsoft.com

Вы видели новый microsoft.com? Оно теперь больше похоже на поисковик, чем на сайт большой софтверной компании. Я помню, мне стало неприятно, когда однажды зайдя на сайт QIP я обнаружил, что ссылку для скачивания теперь найти намного сложнее, чем завести себе почтовый ящик или узнать прогноз погоды. И вот теперь microsoft. Мне это странно.

Saturday, September 5, 2009

C++ код на blogger.com?

Пока я писал предыдущие 2 поста, после каждой вставки кода мне приходилось плевать на пол и нервно курить. Причиной тому было то, что я использовал какие-то онлайн сервисы чтобы из C++ кода получить HTML с красивой подсветкой. Проблема в том, что подсветив один раз больше это поправить невозомжно.

И вот наконец-то, чудным сентябрьским вечером, я обнаружил что для этой проблемы уже довольно давно есть решение.

Решение примечательно тем, что подсветку делает в рантайме на стороне клиента (написано на JavaScript). Т.е. когда вы пишете HTML, единственное что вам нужно сделать - это засунуть код в тег PRE и вместо значков "меньше" использовать " & l t ; ". Ну это логично.

Вот пример:

#include <iostream>

int main()
{
std::cout << "hello" << std::endl;
}

Я не знаю как это выглядит у вас, но у меня это выглядит чудесно.

Saturday, August 22, 2009

Корень из целого числа в compile-time часть 2

Не так давно в этом блоге мелькала статья на тему вычисления квадратного корня из целого числа в compile-time. Сейчас будет небольшое продолжение.

Некоторое время назад постоянный читатель этого блога прислал мне ссылку на задачку. Сайт Insidecpp иногда очень интересно почитать, и даже пафос и надменность автора как-то можно перетерпеть, когда видишь сколько он там всего понаписал. Прореагировал я примерно так: "чтобы моё решение подошло к этой задаче, нужно исправить всего 1 строчку". А потом задумался.

Автор предлагает реализовать вычисление квадратного корня в compile-time, но только с формулировкой "найти целое, ближайшее к правильному ответу", а не "наибольшее целое, квадрат которого не превышает":
Напишите вычисление квадратного корня в compile-time-е. Чтобы усложнить задачу я предлагаю следующее. Если квадратный корень от заданного числа не может быть вычислен в целых, то вашим результатом должно быть ближайшее целое к реальному результату. Обратите внимание, что речь идет именно о ближайшем целом. То есть не ближайшее меньшее результата, а просто ближайшее. Оно может быть как больше, так и меньше реального результата.


Т.е., если в моей задаче корень из 3 - это решительно 1, то в задаче автора - это должно быть 2. Решение автора меня очень порадовало своей краткостью, но к сожалению это решение при ближайшем рассмотрении оказалось неверным. Сейчас я расскажу как поправить код из предыдущей статьи, чтобы получить решение для задачки с insidecpp.ru.

Пусть дано:
y * y = x
0 < a < y < b
a и b - это целые числа, ближайшие к y. Нам нужно из a и b выбрать число, которое отличается от y минимально.
Т.е. d1=y-a, d2=b-y
Если d1 < d2, тогда нужно выбрать a, если d1 > d2, тогда - b.

т.е. если буквой z обозначить знак, который ставится между d1 и d2 при сравнении, то получим:
d1 z d2
y-a z b-y
2*y z a+b
4*y*y z (a+b)*(a+b)
как известно, y*y это x, т.е.:
4*x z (a+b)*(a+b)
т.к. в нашем случае вместо a и b используются соответственно lo и lo+1, результат:
4*x z 4*lo*lo + 4*lo + 1
или, чтобы избежать переполнения,
4*(x-lo*lo) z 4*lo + 1
если 4*(x-lo*lo) > 4*lo + 1, выбераем - lo+1. Иначе - lo.

Единственное место в коде, которое необходимо поправить - это:

template<unsigned x, unsigned lo, unsigned y>
struct sqrt<x, lo, 1, y, less>
{
enum { value = lo * lo + 2 * lo <= x - 1 ? (lo + 1) : lo };
};

Меняем логику на:

template<unsigned x, unsigned lo, unsigned y>
struct sqrt<x, lo, 1, y, less>
{
enum { value = 4*(x-lo*lo) > 4*lo + 1 ? lo+1:lo };
};

Задача решена.

Monday, August 10, 2009

Корень из целого числа в компайл-тайм

Я люблю С++. Я ненавижу C++. В пользу обоих утверждений можно привести как минимум по десятку доводов, но независимо от того, какие доводы перевесят, C++ - это очень интересный язык. Одной из важнейших особенностей C++ является механизм шаблонов. С одной стороны в сообществе C++ принято говорить, что шаблоны - это мощнейшее средство, которое позволяет свести дублирование кода к нулю. Яркий пример - стандартная библиотека. Думаю, никто не станет спорить, что это вещь крайне полезная и вполне себе удобная. Но с другой стороны, всегда найдутся люди, которые найдут любому средству такое применение, что волосы дыбом становятся (см. хотя бы boost spirit). Хорошее это средство или плохое, в любом случае оно позволяет сделать процесс написания кода крайне увлекательным занятием.

Эта статья о том, как вычислить квадратный корень из целого числа на этапе компиляции.

Если читатель хоть немного знаком с C++, могу предположить, что он уже пробовал реализовать вычисление факториала на этапе компиляции. Например, так:

template<unsigned x>
struct factorial
{
enum { value = x * factorial<x-1>::value };
};

template<>
struct factorial<1>
{
enum { value = 1 };
};

Чтобы вычислить факториал, достаточно написать:
factorial<5>::value

Это выражение обладает всеми свойствами, которыми обладает константа. Значение этого выражения можно использовать для объявления массива, для специализации/инстанциирования шаблонов и для всего чего угодно остального, т.е. значение известно на этапе компиляции.

Но вернёмся к извлечению корня. Вообще квадратным корнем из числа X называется такое неотрицательное число Y, квадрат которого равен X. Для целых чисел эта формулировка не подходит. Мы будем отталкиваться от формулировки: квадратными корнем из целого числа X называется такое наибольшее целое число Y, квадрат которого не превышает X.

Для начала я опишу алгоритм, который мы будем реализовывать. Пусть нам дано цело число x, а корень, который мы ищем - y. Пусть так же даны 2 числа lo и range, такие, что изначально lo = 0, range = x. На каждой итерации работы y будет серединой диапазона и на каждой итерации мы будем этот диапазон корректировать. Вот простой пример:
x=36
1. lo = 0, range = 36, y = lo + range / 2 = 18. 18*18 > 36, значит берём меньшую половину диапазона.
2. lo = 0, range = 18, y = lo + range / 2 = 9. 9*9 > 36, берём меньшую.
3. lo = 0, range = 9, y = lo + range / 2 = 4. 4*4 < 36, берём большую.
4. lo = 4, range = 4, y = lo + range / 2 = 6. 6*6 = 36 - это ответ.

Возможны и другие варианты развития событий, но о них - позже.

Начнём.

template
<
unsigned x, // число, корень которого ищем
unsigned lo = 0, // начало диапазона
unsigned range = x, // ширина диапазона
unsigned y = lo + range / 2 // значение корня для текущей итерации
>
struct sqrt;

Использование шаблонных параметров со значениями по умолчанию позволяет нам делать нужные вычисления. При инстанциировании этого шаблона в виде sqrt<36>, x будет равен 36, lo - 0, range - 36, y = 18. Что делать дальше? Нам нужно каким-то образом реализовать логику выбора - нижняя половина диапазона, верхняя, ответ уже найден. Для этого опишем вспомогательный класс:

// состояние алгоритма sqrt - уменьшать, увеличивать, вычислено
enum state { less, greater, equal };

// получение состояния алгоритма
template
<
unsigned x, // нужное число
unsigned y // кандидат на корень
>
struct sqrt_state
{
enum { value = x == y*y ? equal : (x < y*y ? greater : less) };
};

sqrt_state<x, y> проверяет отношения равенства/неравенства между x и y*y. В случае если y*y < x, результат sqrt_state::value == less, если y*y > x, то greater, иначе equal. Изменим шаблон sqrt следующим образом:

// sqrt
template
<
unsigned x, // число для извлечения корня
unsigned lo = 0, // нижняя граница диапазона
unsigned range = x, // ширина диапазона
unsigned y = lo + range / 2, // середина диапазона
unsigned state = sqrt_state<x, y>::value // состояние алгоритма
>
struct sqrt;

Теперь при инстанциировании шаблона sqrt, ему известно что нужно делать. В случае less он должен обращаться сам к себе, передавая в качестве аргумента верхний поддиапазон, в случае greater - нижний, а в случае equal рекурсия должна заканчиваться, т.к. ответ найден:

// квадрат проверяемого числа меньше, чем нужное число
template<unsigned x, unsigned lo, unsigned range, unsigned y>
struct sqrt<x, lo, range, y, less>
{
enum { value = sqrt<x, y, range / 2>::value };
};

// квадрат проверяемого числа больше, чем нужное число
template<unsigned x, unsigned lo, unsigned range, unsigned y>
struct sqrt<x, lo, range, y, greater>
{
enum { value = sqrt<x, lo, range / 2>::value };
};

// квадрат проверяемого числа равен нужному числу
template<unsigned x, unsigned lo, unsigned range, unsigned y>
struct sqrt<x, lo, range, y, equal>
{
enum { value = y };
};

Теперь, если проверить написанное с помощью:
sqrt<36>::value

Получим правильный ответ - 6. А если попробовать 37? Ошибка компиляции. Почему? Всё очень просто. Дело дошло до того, когда range стал равным 0. При этом специализация
struct sqrt<x, lo, range, y, less>

попыталась вызвать саму себя с теми же параметрами, с которыми она была вызвана. Как же быть? Тут мы столкнулись с ситуацией, когда целочисленный корень из числа не существует. Добавим ещё одну специализацию sqrt:

// квадрат проверяемого числа меньше, чем нужное число, диапазон равен 1
// наибольшее целое, квадрат которого не превышает заданное
template<unsigned x, unsigned lo, unsigned y>
struct sqrt<x, lo, 1, y, less>
{
enum { value = (lo+1)*(lo+1) <= x ? (lo + 1) : lo };
};

Эта специализация начинает работать когда range=1. Когда это происходит? Когда корень числа находится между двумя целыми числами. Для 37 эти числа - 6 и 7. При вычислении value в этой специализации мы проверяем какое из двух чисел "лучше" подходит - 6 или 7. В данном случае выбераем 6. Вроде бы всё. Проверим как работает наш sqrt для других чисел. Для этого напишем вспомогательный класс static_assert (аналогичная штука уже есть в c++0x, но сделаем вид, что у нас нет c++0x):

static_assert<sqrt<0ul>::value == 0ul>();
static_assert<sqrt<1ul>::value == 1ul>();
static_assert<sqrt<2ul>::value == 1ul>();
static_assert<sqrt<3ul>::value == 1ul>();
static_assert<sqrt<4ul>::value == 2ul>();
static_assert<sqrt<5ul>::value == 2ul>();
static_assert<sqrt<6ul>::value == 2ul>();
static_assert<sqrt<7ul>::value == 2ul>();
static_assert<sqrt<8ul>::value == 2ul>();
static_assert<sqrt<9ul>::value == 3ul>();
static_assert<sqrt<13ul>::value == 3ul>();
static_assert<sqrt<100ul>::value == 10ul>();
static_assert<sqrt<256ul>::value == 16ul>();
static_assert<sqrt<257ul>::value == 16ul>();
static_assert<sqrt<2048ul>::value == 45ul>();
static_assert<sqrt<9801ul>::value == 99ul>();
static_assert<sqrt<65533ul>::value == 255ul>();
static_assert<sqrt<65534ul>::value == 255ul>();
static_assert<sqrt<65536ul>::value == 256ul>();
static_assert<sqrt<999999ul>::value == 999ul>();
static_assert<sqrt<1000000ul>::value == 1000ul>();
static_assert<sqrt<12345678ul>::value == 3513ul>();
static_assert<sqrt<123456789ul>::value == 11111ul>();
static_assert<sqrt<4294836223ul>::value == 65534ul>();
static_assert<sqrt<4294836224ul>::value == 65534ul>();
static_assert<sqrt<0xfffeul*0xfffeul>::value == 0xfffeul>();
static_assert<sqrt<0xfffful*0xfffful>::value == 0xfffful>();
static_assert<sqrt<0x10001ul*0xfffful>::value == 0xfffful>();

Пробуем откомпилировать и... компилятор сообщает нам о множестве ошибок и предупреждений. В чём же дело? Начнём с того, что в некоторых местах происходит целочисленное переполнение.

template
<
unsigned x, // нужное число
unsigned y // кандидат на корень
>
struct sqrt_state
{
enum { value = x == y*y ? equal : (x < y*y ? greater : less) };
};

Видим y*y. Проблема связана с тем, что в случае если unsigned - это 32-разрядное целое без знака, то область определения y для выражения y*y - это 1<<(32/2)-1, т.е. 0xffff. Но это частный случай. В общем случае можно реализовать дополнительный класс, который позволит нам проверять y на невыходимость за границы дозволенного его квадрата:

// проверка не превышение наибольшего числа, которое
// можно возвести в квадрат без переполнения
template<unsigned x>
struct is_greater_than_max_squarable
{
enum
{
max_squarable = (1 << (std::numeric_limits<unsigned>::digits / 2)) - 1,
value = x > max_squarable
};
};

Для использования std::numeric_limits нужно подключить стандартный заголовок limits. Название класса говорит само за себя. Исправим логическую часть алгоритма следующим образом:

// получение состояния алгоритма
template
<
unsigned x, // нужное число
unsigned y, // кандидат на корень
bool y_is_too_large = is_greater_than_max_squarable<y>::value
>
struct sqrt_state;

// y превышает наибольшее, которое можно возводить в квадрат
template<unsigned x, unsigned y>
struct sqrt_state<x, y, true>
{
enum { value = greater };
};

// y не превышает наибольшее, которое можно возводить в квадрат
template<unsigned x, unsigned y>
struct sqrt_state<x, y, false>
{
enum { value = x == y*y ? equal : (x < y*y ? greater : less) };
};

Идея в том, что квадрат числа, большего чем 0xffff даст число, большее чем умещается в переменной типа unsigned. Наша модификация заставляет sqrt_state расценивать число как слишком большое в случае если оно больше, чем 0xffff.

Снова компилируем и... снова ошибка. На этот раз одна. Речь идёт о строке:
static_assert<sqrt<0x10001ul*0xfffful>::value == 0xfffful>();

Что же здесь могло произойти? Реальная проблема находится здесь:
enum { value = (lo+1)*(lo+1) <= x ? (lo + 1) : lo };

lo у нас вполне может оказаться равным 0xffff, соответственно (0xffff+1)*(0xffff+1) это 0x10000*0x10000 - а это много. Проблема решается следующим волшебным образом:
enum { value = lo * lo + 2 * lo <= x - 1 ? (lo + 1) : lo };

В таком варианте переполнения не происходит, хотя исправленное условное выражение означает то же самое, что и исходное. Кстати, вопросы по поводу разницы между a+b+c и a+c+b иногда задают на собеседованиях :)

В качестве заключения: sqrt.