3

I have a situation where I would like to define a specialization to be the same as the instantiation of another class. Here's a simple example of what I want (a full intantiation in this example; in my actual problem, I want a partial specialization):

//Template class
template <int i> class Foo { /*...*/ };

//Another, completely different, template class
template <int i,int j> class Bar { /*...*/ };

//Ordinary specialization of Foo
template <> class Foo<0> { /*...*/ };

//Bogus specializations of Foo that
//  hopefully explain what I want.
template <> class Foo<1> = Bar<1, 11>;
template <> class Foo<2> = Bar<2, 42>;
template <> class Foo<3> = Bar<3,-71>;
...

What would be the advantage of doing this? The definitions of Foo<1>, Foo<2>, etc. are fairly complicated, but easily written once as a template. There are a lot of such definitions. Working the definition of Bar into Foo isn't an option. Only some values can be specialized, and the specialization of Bar must be hand-chosen (hence the random numbers for int j).

I would ordinarily achieve this effect by using CRTP. I would make some fairly nasty modifications to Bar, and then do something like:

template <> class Foo<1> : public Bar<1, 11,Foo<1>> {};
template <> class Foo<2> : public Bar<2, 42,Foo<2>> {};
template <> class Foo<3> : public Bar<3,-71,Foo<3>> {};
...

Obviously, Bar would need to be altered, with maybe some using declarations to pull the constructors down. This would be messy.

My question: can I do better than this? That is, can a specialization be defined to be an instantiation of another template class?


Note: preferred standard is C++14, although later versions would be acceptable.

kfsone
  • 23,617
  • 2
  • 42
  • 74
geometrian
  • 14,775
  • 10
  • 56
  • 132
  • Should the `Foo` or `Bar` types have any knowledge of each other? That is, CRTP would allow `Bar` to "know" about `Foo` and `Foo` "knows" about `Bar` because it inherits from it (in your example). But you're wanting an essential `typedef`, so that any and all references to `Foo<1>` would be as if one wrote `Bar<1, 11>`, correct? – txtechhelp Apr 29 '16 at 03:19
  • @txtechhelp Prettymuch. I thought about calling this question something about typedefs, but typedefs don't work afaik for specializations.¶ I'm currently writing `Bar`, so `Bar` can know about `Foo`. The base definition of `Foo` shouldn't know about `Bar`, though--only its specializations, which I am also defining. – geometrian Apr 29 '16 at 03:24
  • Check out the answer to [this](http://stackoverflow.com/questions/20419869/is-it-possible-to-define-an-implementation-template-specialization-as-typedef-of) question .. might have to add a little extra, but it might get you closer? – txtechhelp Apr 29 '16 at 03:27
  • @txtechhelp I think my question must be a dupl of that one. The accepted answer would definitely work for me. It's not nearly as elegant as I would like, but it might be marginally better than the CRTP solution. – geometrian Apr 29 '16 at 03:41

2 Answers2

1

Would indirection help here? :)

template<int i> struct Indirection { using type = Foo<i>; };

template <> class Indirection<1> { using type = Bar<1, 11>;  };
template <> class Indirection<2> { using type = Bar<2, 42>;  };
template <> class Indirection<3> { using type = Bar<3, -71>; };

template<int i>
using ActualFoo = typename Indirection<i>::type;
melak47
  • 4,772
  • 2
  • 26
  • 37
0

You could use inheritance instead of CRTP.

template <int i> struct Foo {};

template <int i,int j> struct Bar { Bar() {} };

template <> struct Foo<0> {};

template <> struct Foo<1> : public Bar<1, 11> { using Bar::Bar; };
template <> struct Foo<2> : public Bar<2, 42> { using Bar::Bar; };
template <> struct Foo<3> : public Bar<3,-71> { using Bar::Bar; };
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • This is essentially exactly what I wrote above, but without CRTP.¶ The reason for CRTP is that e.g. `Bar<1,11>` has methods that should act like `Foo<1>`. For example, `Bar` might define `static Bar getBarPlusBar(Bar,Bar);`. Using CRTP this becomes `static FooType getBarPlusBar(FooType,FooType);`, which means I can now go `Foo<1> foo3 = Foo<1>::getBarPlusBar(foo1,foo2);` – geometrian Apr 29 '16 at 03:30
  • @imallett, you have two choices. Pick the one that meets your needs the best. – R Sahu Apr 29 '16 at 03:33