0

I recently discovered the auto and decltype() features of C++11, which are excellent, as they allow eliminating a lot of redundant type code. However, there are contexts where they cannot be used. One example I'm primarily asking about is if you want to declare a variable whose type uses the enclosing class type, either directly, or as a template argument, and you don't have an initialization expression (which would have allowed you to use auto). This is particularly undesirable if the enclosing class type is a template class with many template parameters. For example:

template<typename T1, typename T2, typename T3, typename T4, typename T5 > struct S {
    std::map<int,S<T1,T2,T3,T4,T5>*> m1;
    std::map<int,S<T1,T2,T3,T4,T5>*> m2;
    std::map<int,S<T1,T2,T3,T4,T5>*> m3;
    std::map<int,S<T1,T2,T3,T4,T5>*> m4;
    std::map<int,S<T1,T2,T3,T4,T5>*> m5;
};

A logical solution is to use a typedef:

template<typename T1, typename T2, typename T3, typename T4, typename T5 > struct S {
    typedef S<T1,T2,T3,T4,T5> ThisClass;
    std::map<int,ThisClass*> m1;
    std::map<int,ThisClass*> m2;
    std::map<int,ThisClass*> m3;
    std::map<int,ThisClass*> m4;
    std::map<int,ThisClass*> m5;
};

But it's still undesirable to have to declare a typedef that just repeats the enclosing class's type.

This can actually be solved if you're inside an instance method, by deducing the type of *this, although the necessary code is more verbose than I would like:

auto copy(void) {
    typename std::remove_reference<decltype(*this)>::type s = *this;
    // ... do stuff with s ...
    return s;
}

This solution does not work in class scope, because this is not allowed and is not meaningful outside of instance methods (the compiler complains "invalid use of ‘this’ at top level").

So, my question is, when you can't use auto or decltype(), what is the recommended solution for avoiding repetition of the enclosing class's type when you have to use it inside the class definition? Is a typedef the only option?

bgoldst
  • 34,190
  • 6
  • 38
  • 64
  • I'm tempted to say that this is effectively a duplicate of http://stackoverflow.com/q/21143835/560648. What do we think? In particular the solutions there may not work seeing as your `S` here is a class template. – Lightness Races in Orbit Feb 08 '15 at 01:13
  • They're related questions, but I would say my question is more general, since I was asking about how to avoid repetition of the class type, theoretically by any means (e.g. type deduction), and not specifically about getting a `self` alias, although that could be a solution. – bgoldst Feb 08 '15 at 01:38

1 Answers1

6

No need to repeat the template parameters if you are referring to the current instantiation.

template<typename T1, typename T2, typename T3, typename T4, typename T5 > struct S {
    std::map<int,S*> m1;
    std::map<int,S*> m2;
    std::map<int,S*> m3;
    std::map<int,S*> m4;
    std::map<int,S*> m5;
};

The injected-class-name S refers to the current instantiation, in this case S<T1, T2, T3, T4, T5>.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • Very nice, I didn't know that! That certainly helps. But the class name must still be repeated. Is there any way to avoid repeating the class name throughout the class definition? – bgoldst Feb 08 '15 at 01:00
  • 1
    @bgoldst I don't understand your question. You have to use *something* to refer to the class type - what could be clearer than the actual type? – Barry Feb 08 '15 at 01:08
  • 1
    I suspect the OP wants something like "self" in case the class name changes later. No, I'm pretty sure that kind of thing doesn't exist in C++. Maybe it'll be added when C++ gets reflection... – Brian Bi Feb 08 '15 at 01:09
  • @Brian, correct, that's exactly what I was looking for. I guess I'll have to repeat the class name, which is not so bad now that I know the template parameters do not have to be repeated. Thanks! – bgoldst Feb 08 '15 at 01:12