[Trick] Автоматическое определение неиспользуемых заголовков
От: remark Россия http://www.1024cores.net/
Дата: 21.01.07 09:30
Оценка: 74 (4) :)
[M$ SPECIFIC]

Больше не надо никаких внешних тулзов и ручного вычищения неиспользуемых заголовков!

Допустим есть следующий заголовок некой библиотеки:
void lib_init();
void lib_deinit();
void lib_f();



Меняем заголовок на следующий:

template<int id> struct lib_helper 
{
    typedef int fake;
};

template<int id = 0> class lib_ind
{
    typedef typename lib_helper<id>::fake fake;
};

template<int id> struct lib_magic
{
    lib_magic()
    {
#ifdef _MSC_VER
        __if_not_exists(lib_helper<id>)
        {
            // Этот заголовочный файл включён зазря
            BOOST_STATIC_ASSERT(false);
        }
#endif
    }
};

static lib_magic<0> lib_magic_;


lib_ind<> lib_init();
lib_ind<> lib_deinit();
lib_ind<> lib_f();



Уаля! Если этот заголовок включит какая-либо единица трансляции, которая не вызывает ни одной из функций lib_init/lib_deinit/lib_f, то она не скомпилируется!

Несколько замечаний:
1. Этот заголовок можно использовать и с другими компиляторами, благодаря #ifdef _MSC_VER, просто не будет работать фича определения неиспользуемых заголовков
2. Если функции библиотеки должны возвращать какое-то значение, а не void, то это можно легко прикрутить к классу lib_ind, тогда просто функции будут выглядеть как lib_ind<bool> lib_init()
3. Всю эту бойду можно вынести в отдельный повторноиспользуемый заголовочный файл. Тогда в заголовке библиотеки надо будет написать примерно так:
PREVENT_UNUSED_HEADERS(my_lib_name);

4. Эту технику можно распространить и на заголовочные файлы, которые описывают классы. Но тут надо проявить немного фантазии, куда впихнуть lib_ind<>. Вообще место, куда впихнуть lib_ind<> в каждом конкретном классе, должно быть разным, и будет зависеть от того, что подразумевается под "использованием" класса, т.к. для классов это не так тривиально, как для функций. Например такой вариант:

template<int id = 0>
struct lib_class
{
    BOOST_STATIC_ASSERT(!id);
    lib_class(lib_ind<> fake = lib_ind<>());
};


требует обязательного создания экземпляров класса. Причём создание, например, указателей на класс не будет засчитываться за использование!
Или можно, например, все функции-члены записать аналогично свободным функциям:
struct lib_class
{
    lib_ind<> f1();
    lib_ind<> f2();
};




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.