0

Targeting Visual Studio C++ 2008

The situation: I have a template class with a large number of parameters, many with defaults.

template <typename A, typename B = b, typename C = c>
struct Outer
{
    typedef typename A typeA;
    typedef typename B typeB;
    typedef typename C typeC;
};

So good so far. Now, I have a user defined type consisting of lots and lots of Outers. In this situation, the types A and B are known, C is not.

My first approach with dealing with this was just to replicate A and B inside the new user type.

template<typename A, typename B>
struct UserDefinedType {
    Outer<A, B, int> AnIntOuter;
    Outer<A, B, float> AFloatOuter;
};

This works, but gets boring rather quickly. (as well as other complexities from the real code). I was thinking... why not create a new inner class using the template parameters that was passed in as default values, so I tried doing this:

template<typename A, typename B>
struct AnotherUserDefinedType {
    template<typename CC, typename AA = A, typename BB = B>
    struct Inner : public Outer<AA, BB, CC> {};

    Inner<int> AnIntInner;
    Inner<float> AFloatInner;
};

When I try compiling this, I get a 'too few template arguments' error which seems to be attached to the declaration of the member (AnIntInner in this case).

What I want to know: Is this (using template parameters of the outer class as default template parameters of the inner class) even remotely possible?

If it IS possible, is my construction wrong or are there known issues with MSVC++ 2008? Or, of course, if I probably have something else wrong in my code as well

UPDATE

Ahh, assisted 20/20 hindsight is always great. I see that I have at least a hat trick of issues with my question and the answer I really needed.

First, @DyP was correct in calling out for an SSCCE even though I was only missing five lines for a complete example (one if I was entering the obfuscated C++ contest) I had looked at my code and said "This looks right, so it must that new thing that I tried that causes problems" and I didn't even build my own example. I need to work on my compiler issued template error message interpreting-fu (oh yeah, and the ass-u-me-ing part...).

However, as @nickie politely doesn't say, that construct is redundant. Default template parameters have their place, but here, it's not even needed. The inner class has visibility of the template parameters used in the outer class. It's way better to only template the parameters I need to be 'free'. I think @nickie answered the question perfectly even though technically I wasn't wrong in the first place, so @nickie's answer gets the checkmark.

That doesn't end things though. @DyP correctly intuited my real problem which is that I wanted to curry some of the template parameters (re-copying the outer template parameters here does have its uses where we want the option of varying the template parameter rather than tightly binding it as real currying does (well, the curried parameter could be a functor... but I digress)). I just needed the type, not to extend the class. The problem with inheritance is that it breaks some overrides, namely operator=().

So, combining the inputs of all three of us, this construct is what I ended up using

template<typename A, typename B>
struct FinalUserDefinedType {
    template<typename C, typename AWithDefault = A>
    struct CurryType {
        typedef Outer<AWithDefault, B, C> type;
    };

    CurryType<int>::type AnIntOuter;
    CurryType<float>::type AFloatOuter;
    CurryType<double, int>::type AnOverriddenDefault;
};

UPDATE 2

fool me once, shame on ME, fool me twice, send me to the ninth circle.

Once again, I didn't compile the example I gave. Eliding from my real code (@DyP caught this once again...), the example should be:

template<typename A, typename B>
struct FinalUserDefinedType {
    template<typename C, typename AWithDefault = A>
    struct CurryType {
        typedef Outer<AWithDefault, B, C> type;
    };

    typename CurryType<int>::type AnIntOuter;
    typename CurryType<float>::type AFloatOuter;
    typename CurryType<double, int>::type AnOverriddenDefault;
};

For virtual bonus points, is it possible to declare AnIntOuter, et al without use of typename?

paulluap
  • 313
  • 4
  • 14
  • `typedef typename A typeA;` no `typename` here, please. (see [this question](http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords)) – dyp Sep 04 '13 at 20:59
  • Please provide an [SSCCE](http://sscce.org). [This example](http://ideone.com/oOIsi6) compiles fine on VS2008. – dyp Sep 04 '13 at 21:02
  • Btw: you don't need to inherit from `Outer`, you can also use a typedef: `template struct Inner { typedef Outer type; };` and then `typename Inner::type AnIntInner;` – dyp Sep 04 '13 at 21:04
  • I know VS2008 doesn't require or enforce it, but you should really use a `typename` here: `typename CurryType::type AnIntOuter;` (etc.) Otherwise, your code won't be portable, and you might even run into compiler problems (at least I guess from my experiences). [Live example](http://coliru.stacked-crooked.com/a/0b755a5414c9cc37) – dyp Sep 05 '13 at 15:54

1 Answers1

3

I think that's the right way to do what you want (if I have understood what that is correctly):

template <typename A, typename B = b, typename C = c>
struct Outer
{
    typedef A typeA;
    typedef B typeB;
    typedef C typeC;
};

template<typename A, typename B>
struct AnotherUserDefinedType {
    template<typename C>
    struct Inner : public Outer<A, B, C> {};

    Inner<int> AnIntInner;
    Inner<float> AFloatInner;
};
nickie
  • 5,608
  • 2
  • 23
  • 37