Сообщение Re: static lib. force linkage от 26.03.2015 15:43
Изменено 26.03.2015 15:52 zaufi
как уже было справедливо замечено, выбранный путь череповат граблями да и просто "некрасив".
когда имеем кучу классов, которые нужно регать где-то там, применяем паттерн "static constructor" (искать по этому форуму).
тогда код инициализации будет жить в самом классе (в статической функции, которая будет "автоматом" вызываться просто по факту объявления класса).
итак:
вот тебе пример с использованием статического конструктора (авторство уточнить поиском по форуму):
пример работы:
... не за что ...
когда имеем кучу классов, которые нужно регать где-то там, применяем паттерн "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" (искать по этому форуму).
тогда код инициализации будет жить в самом классе (в статической функции, которая будет "автоматом" вызываться просто по факту объявления класса).
итак:
вот тебе пример с использованием статического конструктора (авторство уточнить поиском по форуму):
пример работы:
Дальнейшие улучшения: если "статический деструктор" не нужен, можно заморочиться и определять в compile time присутствует ли в Derived функция static_dtor(), и если нет, порождать static_xtors::helper от соответствующей специализации... ну типа упростить задачу линкеру по выкидыванию пустых функций.
... не за что ...
когда имеем кучу классов, которые нужно регать где-то там, применяем паттерн "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 от соответствующей специализации... ну типа упростить задачу линкеру по выкидыванию пустых функций.
... не за что ...