[Trick] Конструктор класса
От: remark Россия http://www.1024cores.net/
Дата: 03.09.08 19:50
Оценка: 264 (28) +1 :)
Вначале пример использования:
struct A : class_initializer<A>
{
    static void static_ctor()
    {
        std::cout << __FUNCTION__ << std::endl;
    }

    static void static_dtor()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

struct B : class_initializer<B>
{
    static void static_ctor()
    {
        std::cout << __FUNCTION__ << std::endl;
    }

    static void static_dtor()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

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


Выводит:
A::static_ctor
B::static_ctor
main
B::static_dtor
A::static_dtor


Теперь реализация (для любителей хардкорного С++):
template<typename derived_t, typename target_t = derived_t>
class class_initializer
{
    struct helper
    {
        helper()
        {
            target_t::static_ctor();
        }

        ~helper()
        {
            target_t::static_dtor();
        }
    };

    static helper helper_;

    static void use_helper()
    {
        (void)helper_;
    }

    template<void(*)()>
    struct helper2 {};

    helper2<&class_initializer::use_helper> helper2_;

    virtual void use_helper2()
    {
        (void)helper_;
    }
};

template<typename derived_t, typename target_t>
typename class_initializer<derived_t, target_t>::helper 
    class_initializer<derived_t, target_t>::helper_;


Основная идея достаточна прямолинейна — создаём статическую переменную, конструктор которой вызывает static_ctor(), а деструктор static_dtor(). Но дьявол, как говорится, в деталях. Как заставить компилятор инстанциировать статическую переменную шаблонного класса, так сказать, "изнутри" этого же класса? У меня на это ушло примерно 2 года непрерывных медитаций
Понятно, что надо как-то использовать эту статическую переменную (helper_), что бы заставить компилятор её инстанциировать. Со студией всё достаточно просто. Достаточно создать виртуальную функцию (use_helper2), которая упоминает статическую переменную. По стандарту будет ли инстанциироваться виртуальная функция — implementation defined. Но студия инстанциирует, поэтому всё замечательно.
Основная засада с gcc, т.к. он, сволочь, не инстанциирует виртуальные функции шаблонных классов без особой надобности. При наследовании от шаблонного класса гарантированно по стандарту инстанциируются только объявления всех членов. Поэтому надо как-то из объявления члена класса использовать статическую переменную. Решение следующее. Параметризуем вспомогательный шаблонный класс (helper2) адресом статической функции (use_helper). Поскольку от функции берётся адрес, gcc её инстанциирует (логично). Далее просто — функция упоминает статическую переменную (helper_).
В принципе тут можно пойти более коротким путём — параметризовать вспомогательный класс сразу адресом нужной статической переменной (helper_). Но я столкнулся с тем, что не все компиляторы хорошо это переваривают, хотя на некоторых gcc это работает как полагается.
В итоге это решение работает на msvc7.1, msvc8, msvc9, gcc3.4, gcc 4.1. На Comeau online — компилируется без ошибок, что радует.



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