Partial Template Specialization

I have a situation where I will have multiple classes that are all pretty much the same, but have different underlying types. The obvious solution here is to use a class template.

The problem is, I want some of the classes to have additional functions. For example Foo<int> should have all the same functionality as Foo<float> plus some additional functions.

How can I do this without repeating tons of code?

A few things to note:
- This template class is limited to a specific number of types, and the class won't actually be used as a template, but instead the user will use one of many typedefs (ie: FooInt or FooFloat instead of Foo<int> or Foo<Float>).


My initial thought was to create a base class that has all the main functionality, and simply derive FooInt from that:

1
2
3
4
5
6
7
8
9
10
11
12
13
template <typename T>
class FooBase
{
  // all functionality here
};

typedef FooBase<float>  FooFloat;  // float has no added functionality

class FooInt : public FooBase<int>
{
public:
  void AdditionalFunction();  // but FooInt has an added function or two
};


This plan seems like a winner EXCEPT for the fact that constructors and assignment operators (of which I will have SEVERAL) are not inherited. Which means I'd need to make a bunch of bunk ctors/assignment operators for FooInt.

Were it just one class that needed this kind of specialization, it wouldn't be a problem, but I plan on having 3 or 4 of them, each differing only in that one function.


My next thought was to macro it:

1
2
3
4
5
6
7
8
9
10
11
12
13
#define CTORSANDASSIGNMENTS( Type )   \
  Type() { DefaultCtor(); } \
  Type(int) { AnotherCtor(); } \
  Type& operator = (const Type& r) { Assignment(r); } \
  // etc

class FooInt : public Foo<int>
{
public:
  CTORSANDASSIGNMENTS( FooInt );

  void AddedFunction();
};


But ugh. Would that really be necessary?

Can anyone suggest a better approach?

Thanks!

EDIT: After googling it appears "partial template specialization" probably isn't the right term for the above... but I don't know what else to call it, so yeah.
Last edited on
Your initial thought is correct.

A template makes things that all look identical except for some types. Adding functions given a type is outside a template's purview.

Macros are ugly. Just copy and paste the ctors for the derived classes. Its cleaner.

Hope this helps.
Macros are ugly. Just copy and paste the ctors for the derived classes. Its cleaner.


I don't know... duplicate code is pretty freaking ugly. And much harder to maintain than a macro.

A macro will muck up intellisense, but at least it keeps all of my code in one place.

We're talking 10+ ctors and 10+ assignment operators in ~4 classes. That much copy/pasting should be illegal.

I'm not saying a macro is a good solution. But I don't know if it's any worse than massive code repetition.

Are those really my only 2 options?
closed account (1yR4jE8b)
Why not have "do nothing" methods that have template specializations for the types that you want to have the added functionality?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template <class T>
class Foo
{
public:
	void doSomething();
	
	//rest of class	
};

template <class T>
void Foo<T>::doSomething()
{
         ; //do nothing or possibly throw some kind of "not implemented" exception
}

template <>
void Foo<int>::doSomething()
{
	//do stuff
}
Last edited on
Because I don't want the functions exposed to the user. If they try to use the bad function I want it to give them an error, not quietly do nothing (and/or return garbage).
closed account (1yR4jE8b)
Throw an exception?

I don't know, personally, it just seems more sane than copying and pasting entire classes or using nasty looking macros. All approaches are valid, it just depends on which tradeoff you want to make.
Last edited on
uhmm i'm not sure what i'm going to say is correct and don't have the entire idea in mind..

uhmm, should you make friend or namespace?
Last edited on
@darkestfright:

I don't like the exception idea. This is something that should be detected at compile time. throwing an exception forces you to catch the problem as a runtime error.

A compiler error would be much much better.

Besides... how would I even throw an exception without specializing the template? I might as well abandon templates entirely if I take this route (and if I do that, then I don't need to throw an exception).


@blackcoder:

I don't see how friends or namespaces apply. Can you clarify?
Seriously, I think your design needs rethinking if you want extra functions in a specialization.

In any case, darkestfright had an idea closest to one of my first reactions: derive a specialization "base" class from which the special specializations derive...
Seriously, I think your design needs rethinking if you want extra functions in a specialization.


I guess I'll just spit it out then. Maybe you guys can give a suggestion on a design improvement.

This is for a series of string classes in a general library I'm working on. The idea is I'll have at least 3 different classes: utf8str, utf16str, and utf32str. They all function the same way, but store the strings different internally.

Additionally they're interchangable, so you can do UTF-8 to UTF-16 or whatever conversions with an assignment:

1
2
3
4
5
6
utf8str foo = "Boo";
utf16str bar = foo; // converts to UTF-16

// you can then get pointers for whatever:
const utf8* ptr1 = foo.c_str();
const utf16* ptr = bar.c_str();


Now 99% of the interface is exactly the same for all 3 classes. And I can just have the template call non-templated overloaded functions in another class to do the conversion and type specific stuff.

The problem is i don't want a c_str function as above for type safety reasons. Specifically because I want a more generic 'utfstr' class... the underlying format of which can be changed with a compiler option. The idea is you write your code using utfstr without caring about which underlying format is used, and only use the specific utf8str etc types when you need the raw string data for specific input/output.

If I have this generic utfstr class and the above c_str function, you can easily shoot yourself in the foot by doing this:

1
2
3
utfstr foo = "blech";

const utf8* foo.c_str();  // shot yourself in the foot.  This assumes utfstr uses UTF-8 


That code would compile okay IF utfstr is configured to use UTF-8. But if you change this at a future time to UTF-16 or something, you just broke your code.

So the idea is, utf8str, utf16str, utf32str would all have a c_str (or similar but differently named) function, whereas utfstr wouldn't. Apart from that, they'd be identical.

Additionally... since utf32str is the only one that's really random access friendly, it's the only one I'd want to have a [] operator.

So to sum up:

1
2
3
4
utfstr  :  nothing additional
utf8str :  c_str
utf16str:  c_str
utf32str:  c_str, operator []


Plus I'd want the utf32str iterators to be different from the other class' iterators for the [] operator.



Any input / ideas?

I really appreciate all the help so far, guys! Thanks!
Last edited on
You could pass a second template (template) argument that denotes the base class (template) of your class. In this base class, either c_str is defined or it is not. Then typedef your final classes so the templates don't appear anymore.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template<class T> struct HasNothing {};
template<class T> struct HasCStr { T* c_str() { ... } };

template<class T, template<class> B>
class utfstr_base : public B<T>
{
    ...
};
typedef utfstr_base<char, HasNothing> utfstr;
typedef utfstr_base<utf8, HasCStr> utf8str;
typedef utfstr_base<utf16, HasCStr> utf16str;
...


utf8str u8; utf16str u16; utfstr u;
utf8* c;
c = u8.c_str(); // will compile perfectly
c = u16.c_str();  // will only compile, if utf16 is convertible into utf8
c = u.c_str(); // compile error: function not found. 



Some comments why you shouldn't use my idea:
- error messages will suck hard!
- Good luck figuring out how to implement HasCStr::c_str. :-P
- this use of a base class is violating Liskov's substitution principle. Better not tell anyone about "HasCStr" at all..
- this example is for one optional function. You have to use either use multiple inheritance (which some people consider to be 'evil') or "enumerate" all combinations of "functions or not" which can get messy quickly.
That is a VERY interesting idea.

Very interesting indeed. I might just do that.

Implementing the functions from the parent class shouldn't be that difficult -- I can just downcast 'this'.

The error messages are kind of a problem, yeah, but pretty much any error message with templates is going to suck.

I can see it getting messy quickly, but it won't be that bad because there will only be the 3 different situations (HasNothing, HasCStr, HasCStrAndBrackets)


This might just be the answer I was looking for. Not perfect, of course, but it beats macros and massive copy pasting for sure.

Thanks a ton, imi!
Since everyone here is working on UTF stuff (myself included), maybe we should put our work together...

Personally, I dismissed the UTF string class just because it got messy fast, and I think UTF conversions only need to be done when reading/writing data to external sources. Should you need to do internal en/de/coding, a stringstream will help with that... (So, I'm working on UTF facets... heh...)
Well what I'm working on is part of a larger library.

I'm writing something that's geared more towards usage in a game and not really for heavy string manipulation. Strings would mainly be used for things like filenames, dialogue, menus, and printing stats.

The idea was to make Unicode support a no brainer in a situation where direct text manipulation is unnecessary. My string classes will be supported by other areas in the library which read blocks of dialog from text files and the like.. and other areas in the lib use them (file names and stuff)

My class wouldn't be practical / applicable to other situations where you'd need to do a lot of text manipulation, or where you'd need massive strings (thousands and thousands of characters).

Plus I kind of gutted all my old string code and am rewriting it now (had some issues with it before) so I don't have much to show right now.

I'd be more than happy to show what I have when it's done. I don't get much time to code anymore, though, so it might take a while.


(Ironically, my library started as a frontend for libvorbis to make it easy to play background music and sound effects. The resulting audio classes evolved so much I decided to expand the lib to other areas)
Last edited on
You guys *do* know that C++0x will include full and direct support for UTF literals, right?

http://en.wikipedia.org/wiki/C_0x#New_string_literals
That doesn't answer the problem of UTF conversion and string handling.

Also, you can use UCP literals right now:
L"\U0001D11E" --> G clef symbol
(Note that this symbol is outside the BMP)

On systems where wchar_t is 16-bits, the string literal gets encoded as UTF-16.
On systems where it is 32-bits, the string literal gets encoded as UTF-32.

It is worth noting that this is a common compiler extension.
Last edited on
Topic archived. No new replies allowed.