02 Ноябрь 2009

Unicode: life-hack

Мой обычный сценарий при создании новых файлов в проекте:
1. right click в Windows explorer на папке, где нужно создать файл
2. выбор Create/"New Text File.txt"
3. ввод имени файла
4. right click на файле
5. SVN/Add
6. Перетаскивание файла в IDE

Небольшой лайф-хак позволяет сразу создавать файлы в UTF-8:

Файл создается с BOM для UTF-8.

21 Октябрь 2009

Yo!

Отсортировать строки по алфавиту очень просто - все необходимые сведения о порядке символов есть в классе std::locale. Остается только надеяться что std::locale не подведет. А, как оказалось, она может. Вот пример:
struct lexicographical_order
{
std::locale Locale;

lexicographical_order(std::locale Locale) : Locale(Locale)
{
}

bool operator()(std::wstring const &lhs, std::wstring const &rhs) const
{
return boost::ilexicographical_compare(lhs, rhs, Locale);
}
};

int main()
{
std::vector v;
v.push_back(L"яблоко");
v.push_back(L"апельсин");
v.push_back(L"банан");
v.push_back(L"персик");
v.push_back(L"ёжик");

std::locale Locale(""); // используем текущую локаль системы
std::cout << Locale.name() << std::endl;
std::sort(v.begin(), v.end(), lexicographical_order(Locale));

_setmode(_fileno(stdout), _O_U16TEXT);
std::copy(v.begin(), v.end(), std::ostream_iterator(std::wcout, L"\n"));
return 0;
}

Под русской Windows получаем:
Russian_Russia.1251
ёжик
апельсин
банан
персик
яблоко

Буква "ё" явно пользуется у данной локали большей популярностью, чем все остальные. Ну прям хоть свою локаль пиши...

28 Август 2009

Boost Tuple Serialization

Сложно поверить, но в Boost-е нет сериализации для tuple.

Видимо вся фигня в том, что при сериализации кортежей нужно написать сериализацию для кортежей 0..N элементов, а это можно сделать:
а) руками: написать вручную сериализацию для 0, 1, 2 и т.д. элементов, что совсем не кошерно;
б) препроцессором: использовать boost preprocessor - тоже считается не очень кошерно;
в) компилятор: но тут вся загвоздка как я понял в том, что это нельзя сделать используя публичный интерфейс tuple, можно только зная особенности реализации (details), что тоже вроде бы не очень кошерно.

В результате был выбран списоб "г" - вообще не писать сериализацию для tuple. Что я считаю полным бредом.

PS. Если что - есть готовая реализация через препроцессор.

19 Июль 2009

Sorting by several fields

Как вы сортируете по нескольким критериям?
struct foo
{
A a; B b; C c; D d;
X x; Y y;
};

// нужно отсортировать по a, затем по b, затем по c, ну а затем еще и по d
// по x и y сортировать не нужно
bool s(foo const &l, foo const &r)
{
if (l.a < r.a) return true;
if (l.a > r.a) return false;
if (l.b < r.b) return true;
if (l.b > r.b) return false;
if (l.c < r.c) return true;
if (l.c > r.c) return false;
return l.d < r.d;
}

std::vector<foo> f;
std::sort(f.begin(), f.end(), s);

Признаюсь, я примерно так раньше и сортировал. Хотя по сути-то [a,b,c,d] - это ж по-сути обычный кортеж, а для них уже есть готовые библиотеки. И операции сравнения кортежей там должны быть, в этих библиотеках. Нужно просто загнать l и r в кортежи (только для скорости - не в [A,B,C,D], а в [const&A,const&B,const&C,const&D]), и сравнить:
#include <boost/tuple/tuple_comparison.hpp>

bool s(foo const &l, foo const &r)
{
return boost::tie(l.a, l.b, l.c, l.d) < boost::tie(r.a, r.b, r.c, r.d);
}

16 Июль 2009

Static member definition

Интересно, что статический член класса нельзя определить прямо в декларации класса:
class foo
{
static std::string s('hello world');
};
А иногда сильно этого хочется - например в декларации шаблона. Или просто в каком-нибудь header-only классе. Самое интересное, что внутри функции такое провернуть можно. Поэтому можно сделать финт ушами - сделать доступ к статическому члену через member-функцию:
class foo
{
static std::string &s()
{
static std::string impl('hello world');
return impl;
}
};
Синтаксис при обращении немного поменяется - s() вместо s, но часто оно того стоит.

23 Июнь 2009

Fast parsing

Чем вы парсите всякую "мелочёвку" типа целочисленных значений и прочее? Самописными парсерами с приправами вроде boost::tokenizer, boost::lexical_cast или даже atoi, etc.? Я обычно использовал boost::regex + lexical_cast. А тут недавно посмотрел презентацию Spirit-а с BoostCon-а, даже немного проникся. Раньше как-то я к Спириту более равнодушен был.

Описывать грамматику на C++ и потом давать компилятору [несколько минут] это компилировать - это, конечно, большой изврат. Но весьма забавно. И, говорят, работает потом очень быстро. Даже если нужно просто число распарсить - говорят быстрее всех парсит.
std::string buffer("1234");
int value = 0;

using namespace boost::spirit;
bool r = qi::parse(buffer.begin(), buffer.end(), int_, value);
assert(r && value == 1234);

14 Июнь 2009

Visual Studio debug visualizers

Начиная с Visual Studio 2005 можно писать свои правила для отображения значений в отладчике. Более подробнее об этом можно почитать в блоге virtualdub.

Правила для Boost-овских типов можно найти на Boost Wiki. Единственное, не нашел там то, что искал — для boost::variant. Набросал на коленке:
boost::variant<*,*,*,*,*,*,*,*,*,*,*> {
preview (
#(
#switch($c.which_)
#case 0 ( *($T1 *)&($c.storage_.data_) )
#case 1 ( *($T2 *)&($c.storage_.data_) )
#case 2 ( *($T3 *)&($c.storage_.data_) )
#case 3 ( *($T4 *)&($c.storage_.data_) )
#case 4 ( *($T5 *)&($c.storage_.data_) )
#case 5 ( *($T6 *)&($c.storage_.data_) )
#case 6 ( *($T7 *)&($c.storage_.data_) )
#case 7 ( *($T8 *)&($c.storage_.data_) )
#case 8 ( *($T9 *)&($c.storage_.data_) )
#case 9 ( *($T10 *)&($c.storage_.data_) )
)
)
children
(
#(
value:
#switch($c.which_)
#case 0 ( *($T1 *)&($c.storage_.data_) )
#case 1 ( *($T2 *)&($c.storage_.data_) )
#case 2 ( *($T3 *)&($c.storage_.data_) )
#case 3 ( *($T4 *)&($c.storage_.data_) )
#case 4 ( *($T5 *)&($c.storage_.data_) )
#case 5 ( *($T6 *)&($c.storage_.data_) )
#case 6 ( *($T7 *)&($c.storage_.data_) )
#case 7 ( *($T8 *)&($c.storage_.data_) )
#case 8 ( *($T9 *)&($c.storage_.data_) )
#case 9 ( *($T10 *)&($c.storage_.data_) )
)
)
}