2

I have a potentially recursive templated struct type (effectively a c++11 version of boost::variant), and unfortunately, the nicest workaround I can come up with involves macros, which I would REALLY like to avoid.

So given this type:

template<typename... T>
struct MyType { 
  using MyType_parent_t = Mytype<T...>;
  /*lots more code*/ 
} ;

I want to be able to do the equivalent of the following:

struct value;

using value = MyType<
    bool,
    int,
    float,
    std::string,
    std::vector<value>,
    std::map<std::string,value> 
>;

Now, obviously, this doesn't work, as I can't forward declare a templated struct (which I feel I should be able to in this scenario, but whatever).

Now, here's what I've got right now:

struct value : public MyType<
    int,
    double,
    bool,
    std::string,
    std::map<std::string, value>,
    std::vector<value>
> { INJECT_PASSTHROUGH_WRAPPER_BOILERPLATE(value) };

where INJECT_PASSTHROUGH_WRAPPER_BOILERPLATE(value) will expand to:

value() = default;
value(value const & ) = default;
value(value &&) = default;

template<typename T,
         typename std::enable_if<NonSelf<T, value>()>::type* = nullptr>
value(T && op) : MyType_parent_t(std::forward<T>(op)) { }

value & operator=(value const &) = default;
value & operator=(value &&) = default;
template<typename T,
         typename std::enable_if<NonSelf<T, value>()>::type* = nullptr>
value & operator=(T && val) {
    *static_cast<MyType_parent_t*>(this) = val ;
    return *this;
}

The big problem is that I need the wrapper type to have a forwarding constructor and forwarding assignment, so I need a ton of boilerplate to accomodate it.

I actually kinda dig this solution, as I don't even need a forward declare anything anymore (as long as recursivity is done through containers). I just reaaaaaaaly wish I could pull this off without macros, but at this point, it's time for me to ask for help.

Any suggestions? (I am open to c++14, or even c++1z options if necessary)

  • 3
    Couldn't you use `using MyType::MyType; using MyType::operator=;` instead of your current boilerplate? – dyp Mar 07 '15 at 19:53
  • Wouldn't you be able to put the stuff from `INJECT_PASSTHROUGH_WRAPPER_BOILERPLATE` in a CRTP base class? – Pradhan Mar 07 '15 at 19:58
  • dyp: Yes! I totally forgot about that syntax. –  Mar 07 '15 at 20:05
  • @Frank: Don't dread macros so much - I honestly prefer using a macro to code repetition when there's no language solution that allows me to avoid the redundancy. Just be careful defining the macro and use full-caps names (as you did). I use macros a lot in my codebase: I have a `FWD(x)` macro that expands to `std::forward(x)`; I have a `DEFINE_FAT_ENUM(...)` variadic macro that automatically generates an enum and a helper class to convert from/to strings. This is not *abuse* in my opinion - abuse happens when you needlessly use macros for something that the language could achieve. – Vittorio Romeo Mar 08 '15 at 21:37
  • Recursiveness through containers is bad idea, because [containers does not supply incomplete types](http://stackoverflow.com/questions/18672135/why-c-containers-dont-allow-incomplete-types). You must use something like [`boost::recursive_wrapper`](http://www.boost.org/doc/html/variant/reference.html#header.boost.variant.recursive_wrapper_hpp) to be correct. – Tomilov Anatoliy Mar 10 '15 at 04:30

0 Answers0