Информация об изменениях

Сообщение Re: static lib. force linkage от 26.03.2015 15:43

Изменено 26.03.2015 15:52 zaufi

как уже было справедливо замечено, выбранный путь череповат граблями да и просто "некрасив".
когда имеем кучу классов, которые нужно регать где-то там, применяем паттерн "static constructor" (искать по этому форуму).
тогда код инициализации будет жить в самом классе (в статической функции, которая будет "автоматом" вызываться просто по факту объявления класса).
итак:

вот тебе пример с использованием статического конструктора (авторство уточнить поиском по форуму):
#include <iostream>

namespace pattern {
/**
 * \brief Helper class to inialize static variables w/o explicit variables declaration
 *
 * \note \e 'xtors' in class name means \e ctor (constructor) and \e dtor (destructor)
 */
template <
    typename Derived
  , typename Target = Derived
  >
class static_xtors
{
    struct helper
    {
        helper()
        {
            Target::static_ctor();
        }

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

    static helper s_helper;

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

    static void use_helper()
    {
        (void)s_helper;
    }
    helper2<&static_xtors::use_helper> s_helper2;

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

public:
    virtual ~static_xtors() {}
};

template <
    typename Derived
  , typename Target
  >
typename static_xtors<Derived, Target>::helper
static_xtors<Derived, Target>::s_helper;
}                                                           // namespace pattern

/// Registration related stuff
namespace reg {

/// Some registry for classes
struct registry
{
    /// Dummy implementation. The real one shoud add a given pointer
    /// to some registry...
    template <typename T>
    static void register_it(T* const)
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

/// Generalize registration for any partucular child of this base.
/// Is uses \c static_xtors to make an instance of \c Derived and
/// register it.
template <typename Derived>
struct registrar : public pattern::static_xtors<registrar<Derived>>
{
    static void static_ctor()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;

        static auto* p = new Derived();
        /// \attention Fix it according your case!
        registry::register_it(p);
    }
    static void static_dtor()
    {
        // Nothing to do...
    }
};

}                                                           // namespace reg

/// \note Declare your particular classes and don't care about registration anymore!
/// Adding removing any new class as easy as pie!
namespace test {
struct class_1 : public reg::registrar<class_1> {};
struct class_2 : public reg::registrar<class_2> {};
struct class_123 : public reg::registrar<class_123> {};
}                                                           // namespace test

int main()
{
    std::cout << "Nothing to do in main()" << std::endl;
    return 0;
}


пример работы:
zaufi@gentop〉/work/tests〉g++ -std=c++11 -o static_xtors_test static_xtors_test.cc

zaufi@gentop〉/work/tests〉 ./static_xtors_test
static void reg::registrar<Derived>::static_ctor() [with Derived = test::class_1]
static void reg::registry::register_it(T*) [with T = test::class_1]
static void reg::registrar<Derived>::static_ctor() [with Derived = test::class_2]
static void reg::registry::register_it(T*) [with T = test::class_2]
static void reg::registrar<Derived>::static_ctor() [with Derived = test::class_123]
static void reg::registry::register_it(T*) [with T = test::class_123]
Nothing to do in main()

zaufi@gentop〉/work/tests〉g++ --version
g++ (Gentoo 4.9.2 p1.2, pie-0.6.2) 4.9.2


... не за что ...
Re: static lib. force linkage
как уже было справедливо замечено, выбранный путь череповат граблями да и просто "некрасив".
когда имеем кучу классов, которые нужно регать где-то там, применяем паттерн "static constructor" (искать по этому форуму).
тогда код инициализации будет жить в самом классе (в статической функции, которая будет "автоматом" вызываться просто по факту объявления класса).
итак:

вот тебе пример с использованием статического конструктора (авторство уточнить поиском по форуму):
#include <iostream>

namespace pattern {
/**
 * \brief Helper class to inialize static variables w/o explicit variables declaration
 *
 * \note \e 'xtors' in class name means \e ctor (constructor) and \e dtor (destructor)
 */
template <
    typename Derived
  , typename Target = Derived
  >
class static_xtors
{
    struct helper
    {
        helper()
        {
            Target::static_ctor();
        }

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

    static helper s_helper;

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

    static void use_helper()
    {
        (void)s_helper;
    }
    helper2<&static_xtors::use_helper> s_helper2;

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

public:
    virtual ~static_xtors() {}
};

template <
    typename Derived
  , typename Target
  >
typename static_xtors<Derived, Target>::helper
static_xtors<Derived, Target>::s_helper;
}                                                           // namespace pattern

/// Registration related stuff
namespace reg {

/// Some registry for classes
struct registry
{
    /// Dummy implementation. The real one should add a given pointer
    /// to some registry...
    template <typename T>
    static void register_it(T* const)
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

/// Generalize registration for any partucular child of this base.
/// It uses \c static_xtors to make an instance of \c Derived and
/// register it.
template <typename Derived>
struct registrar : public pattern::static_xtors<registrar<Derived>>
{
    static void static_ctor()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;

        static auto* p = new Derived();
        /// \attention Fix it according your case!
        registry::register_it(p);
    }
    static void static_dtor()
    {
        // Nothing to do... 
        // \attention In this particular example pointer \c p will be leaked!
        // A real code may do cleanup...
    }
};
}                                                           // namespace reg

/// \note Declare your particular classes and don't care about registration anymore!
/// Adding removing any new class as easy as pie!
namespace test {
struct class_1 : public reg::registrar<class_1> {};
struct class_2 : public reg::registrar<class_2> {};
struct class_123 : public reg::registrar<class_123> {};
}                                                           // namespace test

int main()
{
    std::cout << "Nothing to do in main()" << std::endl;
    return 0;
}


пример работы:
zaufi@gentop〉/work/tests〉g++ -std=c++11 -o static_xtors_test static_xtors_test.cc

zaufi@gentop〉/work/tests〉 ./static_xtors_test
static void reg::registrar<Derived>::static_ctor() [with Derived = test::class_1]
static void reg::registry::register_it(T*) [with T = test::class_1]
static void reg::registrar<Derived>::static_ctor() [with Derived = test::class_2]
static void reg::registry::register_it(T*) [with T = test::class_2]
static void reg::registrar<Derived>::static_ctor() [with Derived = test::class_123]
static void reg::registry::register_it(T*) [with T = test::class_123]
Nothing to do in main()

zaufi@gentop〉/work/tests〉g++ --version
g++ (Gentoo 4.9.2 p1.2, pie-0.6.2) 4.9.2


Дальнейшие улучшения: если "статический деструктор" не нужен, можно заморочиться и определять в compile time присутствует ли в Derived функция static_dtor(), и если нет, порождать static_xtors::helper от соответствующей специализации... ну типа упростить задачу линкеру по выкидыванию пустых функций.

... не за что ...