Автоматически генерировать конструкторы на основе нестатических членов данных? - PullRequest
0 голосов
/ 30 марта 2011

Мне надоело писать конструкторы вручную. Как я могу автоматизировать это?

struct MyFunctor {
public:
  MyFunctor(/* repeat what I wrote again!*/)
  :/* repeat what I wrote again! */
  { }

  bool operator()() { return true; }

private:
  Controller *m_controller;
  String m_action;
  bool m_allowRejection;
  /* ... */
};

Ответы [ 6 ]

3 голосов
/ 30 марта 2011

Вы можете отказаться от сокрытия данных и использовать старую добрую инициализацию структуры из C:

struct MyFunctor
{
    Controller *m_controller;
    String m_action;
    bool m_allowRejection;

    bool operator()() const
    {
        return true;
    }
};

MyFunctor fun = {&some_controller, "hello world", false};

В C ++ 0x вы даже можете создавать объекты на лету благодаря равномерной инициализации:

some_function( MyFunctor {&some_controller, "hello world", false} );

... или вы можете переключиться на Scala и использовать первичные конструкторы ;)

1 голос
/ 30 марта 2011

Такой макрос может быть полезен, хотя, возможно, и уродлив:

#include <boost/preprocessor.hpp>

#define AUTO_CONSTRUCTOR_DETAIL_PARAM(r, data, member) \
        BOOST_TYPEOF(member) member

#define AUTO_CONSTRUCTOR_DETAIL_INIT(r, data, member) \
        member(member)

#define AUTO_CONSTRUCTOR_DETAIL(className, mems) \
        className(BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \
                    AUTO_CONSTRUCTOR_DETAIL_PARAM, BOOST_PP_EMPTY, members))) : \
        BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \
            AUTO_CONSTRUCTOR_DETAIL_INIT, BOOST_PP_EMPTY, member)) \
        {}  

#define AUTO_CONSTRUCTOR(className, members) \
        AUTO_CONSTRUCTOR_DETAIL(className, members)

Использовать как:

struct MyFunctor {
public:
  AUTO_CONSTRUCTOR(MyFunctor, (m_controller)(m_action)(m_allowRejection)) 

  bool operator()() { return true; }

private:
  Controller *m_controller;
  String m_action;
  bool m_allowRejection;
  /* ... */
};

Не проверено, конечно.

0 голосов
/ 30 марта 2011

Если бы вы использовали это исключительно как тип хранения класса, вы могли бы использовать Boost::tuple, который автоматически генерирует такой ctor, так что ваш класс будет выглядеть примерно так:

tuple<Controller, String, bool> MyFunctor;

Проблема в том, что он не предоставляет никакой возможности включить ваш operator(). К сожалению, поскольку ctors не наследуются, вы могли бы , а не выполнить что-либо, пытаясь создать functor_base с использованием boost::tuple, а затем получить класс, добавивший operator().

Очевидной альтернативой будет перезапись tuple, позволяющая указать код для различных функций-членов. Я не уверен, как это сделать сразу же - это потребует некоторых тщательных размышлений (в лучшем случае).

0 голосов
/ 30 марта 2011

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

0 голосов
/ 30 марта 2011

Если вам нужна только инициализация значения, вы можете использовать шаблон, как описано здесь - аккуратно, и вы не повторяетесь.

0 голосов
/ 30 марта 2011

Хм ... Ответ GMan заставил меня задуматься о чередующихся макросах:

#define FOR_EACH_FIELD( macro ) \
   macro( Controller*, m_controller ) \
   macro( String, m_action ) \
   macro( bool, m_allowRejection )

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

struct MyFunctor {
#define FOR_EACH_FIELD( macro ) // as above
   CREATE_CONSTRUCTOR( MyFunctor, FOR_EACH_FIELD ) // this macro will call others.
   bool operator()() {}
private:
   CREATE_FIELDS( FOR_EACH_FIELD );
#undef FOR_EACH_FIELD
};
...