0

I'm sick of writing constructors manually. How can I automate this?

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;
  /* ... */
};
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • You mean you want to accept the types of members and to a direct initialization? – GManNickG Mar 30 '11 at 06:28
  • Do you want the argument list to have `Controller* a_controller, String a_action, bool a_allowRejection`? Would a fugly fugly macro work? – James McNellis Mar 30 '11 at 06:28
  • @James even an editor plugin for kate would work :) – Johannes Schaub - litb Mar 30 '11 at 06:38
  • you can use some code refactoring tool for c++ to speed up writing your code, [good post 1](http://stackoverflow.com/questions/16167/good-refactoring-support-for-c) [good post 2](http://stackoverflow.com/questions/1388469/is-there-a-working-c-refactoring-tool), also [search by google](http://goo.gl/4IGUb). but i not confident that they generate constructors – Taras Mazepa Mar 30 '11 at 06:43
  • 2
    You may want to switch the private and public parts. It's really confusing for the reader to start with "repeat what I wrote again!". I was like "WTF is he talking about?". – fredoverflow Mar 30 '11 at 06:47
  • 1
    How would we automagically know if we should pass parameters by value, const reference, or as a pointer? – Bo Persson Mar 30 '11 at 07:48
  • @Bo: Simply pass everything by reference to const, that should cover the majority of cases. – fredoverflow Mar 30 '11 at 07:58
  • @FredOverflow - But for the m_controller, would I get a reference to a Controller or a reference to a pointer? And I certainly would like an rvalue reference for the String. I'm sure Johannes doesn't want to repeat all parameters if only one should be non-default. :-) – Bo Persson Mar 30 '11 at 08:42
  • @Bo: A reference to a pointer. I would certainly *not* like an rvalue reference for the string, because then I could not pass in lvalues anymore. For efficiently movable types, it would probably be best to pass them by value and then move them from the parameters into the members. – fredoverflow Mar 30 '11 at 08:56

6 Answers6

3

You could give up data hiding and use good-old struct initialization from C:

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

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

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

In C++0x, you can even create objects on-the-fly thanks to uniform initialization:

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

...or you could switch to Scala and use primary constructors ;)

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
1

A macro like this could be of use, though it's arguably ugly:

#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)

Use as:

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;
  /* ... */
};

Untested, of course.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
0

Uhm... GMan's answer got me into thinking on interleaved macros:

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

And then abuse that macro with other macros that add bits and pieces for formatting... I was going to try it, but it becomes a mess quite easily... At any rate my guess is that it is not worth the effort. The final use would be something like:

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
};
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
0

If you only need value-initialization you could use a template as described here - neat and you don't repeat yourself.

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
0

I'm not sure there is an easy answer: at some point, you have to tell the compiler what the initialization values are. For certain frequent patterns, however, you could probably write a simple code generator: you'd provide a file in entry with a three column list: name, type and default initializer, and the compiler would generate the default constructor, the initialing constructor and the data. (It would be simple to extend to allow additional functions.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

If you were using this purely as a storage type of class, you could use Boost::tuple, which automatically generates such a ctor, so your class would look something like:

tuple<Controller, String, bool> MyFunctor;

The problem with this is that it doesn't provide any way for you to include your operator(). Unfortunately, since ctors aren't inherited, you could not accomplish anything by trying to create a functor_base using boost::tuple, then deriving a class that added your operator().

The obvious alternative would be to rewrite tuple allow you to specify the code for various member functions. I'm not sure how to do that right off though -- it would take some careful thought (at best).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111