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 Outer
s. 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
?