С++ Зарегистрируйте переменные члена класса во время компиляции

Я пытаюсь реализовать систему аннотаций в стиле Java, используя boost MPL и fusion.

Зачем это нужно: мне нужно аннотировать переменные-члены, чтобы иметь некоторые специальные функции времени выполнения. Я регистрирую их во время компиляции в моем базовом классе следующим образом:

class foo
{
    INIT()

    $REGISTER("test1")
    int test1 = 5;

    $REGISTER("b")
    char* b = "rndmText";

    ....
}

Моя цель представляет собой комбинацию указателя и текста типа $REGISTER(&a,"a"), но это будущая цель...

Базовый класс обрабатывает все необходимые вещи. Макрос регистра создает вектор слияния:

#define INIT() \    
typedef boost::fusion::vector0<> BOOST_PP_CAT(registered, BOOST_PP_SUB(__COUNTER__,2)); \
boost::fusion::vector0<> BOOST_PP_CAT(list,BOOST_PP_SUB(__COUNTER__,2));

#define EXPORT(arg) \
typedef boost::fusion::result_of::push_back< BOOST_PP_CAT(registered, BOOST_PP_SUB(__COUNTER__,4)), const char*>::type BOOST_PP_CAT(registered, __COUNTER__); \
BOOST_PP_CAT(registered, BOOST_PP_DEC(__COUNTER__)) BOOST_PP_CAT(list, BOOST_PP_SUB(__COUNTER__,1)) = boost::fusion::make_list(BOOST_PP_CAT(list,BOOST_PP_SUB(__COUNTER__,7)), arg);

Это расширяется (в моем случае) до:

    typedef boost::fusion::vector0<> registered18;
    boost::fusion::vector0<> list19;;

    typedef boost::fusion::result_of::push_back< registered18, const char*>::type registered23;
    registered23 list24 = boost::fusion::make_list(list19, "test1");;
    int test1 = 5;

    typedef boost::fusion::result_of::push_back< registered23, const char*>::type registered28;
    registered28 list29 = boost::fusion::make_list(list24, "b");;
    char* b = "rndmText";;

И вот проблема: boost::fusion::make_list(..., "test1") создает ошибку компилятора, и я не знаю, как ее исправить. Это ошибка:

 boost::fusion::joint_view<Sequence,const boost::fusion::single_view<const char *>>::joint_view(const boost::fusion::joint_view<Sequence,const boost::fusion::single_view<const char *>> &)' : cannot convert argument 1 from 'boost::fusion::list<T,const char (&)[6],boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>' to 'const boost::fusion::joint_view<Sequence,const boost::fusion::single_view<const char *>> &'

Может ли кто-нибудь помочь мне или иметь лучшую идею?

Доминик


person Matyro    schedule 02.10.2014    source источник


Ответы (1)


Это не очень помогает с ошибкой компиляции (извините), но это было слишком долго для комментария.

Может кто-нибудь помочь / или есть идея получше?

Я думаю, что вы злоупотребляете макросами. Вместо этого рассмотрите этот клиентский код:

class foo: public registered<foo> {

    int test1 = 5;
    char* b = "rndmText";

public:
    foo();
    virtual ~foo() = default;
};

foo::foo() : registered<foo>{ "foo" } {
    register(&i, "i"); // part of the interface of the base class
    register(&b, "b");
}

Объяснение:

Та же функциональность теперь предоставляется базовым классом. Реализация CRTP означает, что если у вас есть два (или более) класса, наследуемых от registered, они не в той же иерархии классов (поскольку добавление метаданных не должно навязывать классовые отношения между несвязанными конкретными классами).

Реализация registered<T> может использовать boost::fusion внутри (или что-то еще, если вам это нужно) и может скрывать трехметровые объявления за удобным псевдонимом (например, using data_sequence = boost::fusion::vector0<>).

Часть INIT() будет естественной при создании экземпляра registered<T> (и общедоступного интерфейса).

Эта реализация полностью исключает использование макросов и позволяет более элегантно предоставлять метаданные клиентскому коду, например, путем простого импорта из API registered<T>.

person utnapistim    schedule 02.10.2014
comment
Это очень близко к моему первому (не опубликованному) решению. С помощью макросов я надеюсь переместить функцию регистрации ближе к объявлению члена класса для лучшей читабельности. - person Matyro; 02.10.2014
comment
@Matyro: звучит как благородная цель, но я не думаю, что макросы, которые вы написали, помогают с удобочитаемостью ... - person André Caron; 03.10.2014
comment
Фоновый источник для большинства людей менее важен, передний должен выглядеть хорошо :p - person Matyro; 03.10.2014
comment
@Matyro, ты стреляешь себе в ногу с такими мыслями. Примите во внимание два аспекта: во-первых, вы проведете много времени за время существования проекта за кулисами различных интерфейсов (это код, над которым вы будете работать — как вы хотите, чтобы он был простым? изменить или не имеет значения?); во-вторых, если вы напишете минимальную документацию по API, ваши клиенты будут полагаться на нее, а не на заголовочные файлы. Вы также должны оптимизировать файлы заголовков для простоты обслуживания (макросы здесь больше вредят, чем помогают). - person utnapistim; 03.10.2014