简体   繁体   中英

Automatically generate constructors based on non-static data members?

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

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

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.

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
};

如果您只需要值初始化,则可以使用此处所述的模板-简洁,无需重复。

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM