I'm currently writing some classes for use in a minimal radiosity system. Among these, there is an indispensable class for representing three-dimensional vectors. Implementing such a thing for one specific type is quite easy, but for the sake of practice I'd like to create a template class which supports all numeric types that make sense. The class is supposed to support all common operations like the dot and cross products a.s.o..
What I want to do, is to restrict the possible types of the arguments the template class can be passed, to be able to check for incompatible types at compile-time. For instance a Vector3<bool> should not be possible.
Since I'm fairly new to the concept I tried to find solutions on the web and on the forums. I found that using the traits patterns seemed to be the way to do it. Is that correct? I didn't quite get how traits classes etc. work and documentation seems to be less than adequate.
Is using a template the right way to go for the described purpose, or should I prefer implementing an abstract vector class and derive specialized sub-classes - like for instance the Point2D.Float type in Java derived from Point2D? Any completely different suggestions?
Well, I suppose float and double are indisputable. A short int and int implementation could also come in handy, i.e. when defining axis-aligned geometry that isn't really depending on floating point precision or for defining two-dimensional view-aligned interface elements.
In conclusion: short int, int, float, double.
If you decide templates aren't the right way, could you simply state if it's possible to restrict the set of type applicable to a template and a short hint on corresponding techniques?
It's possible. You'll probably want to use type traits.
Here's an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
struct true_type {};
struct false_type {};
template< typename T >
struct is_vectorable {
typedef false_type value;
};
template<>
struct is_vectorable<float> {
typedef true_type value;
};
// Etc. for other allowed types
// This now gives you a type whose "value" member evaluates to
// "true_type" for those types you wish to allow and "false_type"
// for those types you wish to disallow.
The next thing you need to do is create a template and specialize it
only for true_type, but NOT for false_type.
Then, when you attempt to instantiate the template on a type which
evaluates to "false_type", you'll get a compile error because no
specialization exists.
WARNING: This is all off the top of my head. I'm trying to remember
how boost does it without looking. You might want to look at the
boost type_traits library for specific examples.
Personally, I think you are making a mistake and wasting your time.
You cannot possibly presume to know every possible valid combination of types that the user of your class may wish to use. What if he wants to create a Vector3 <MyBigNumType> ? By limiting his choices, you make your class less usable. Further, it should not fall on you to to prevent your users from trying to do stupid things; let the compiler/runtime fail for them the way it is designed to do.
Spending time to prevent people from doing dumb things is not a good way to spend your time. It is better spent recovering from stupid stuff -- and in this case, that is already done for you.
Duoas: I agree with your concerns about too restrictive design choices and about worrying too much, but as I said before, using the template approach and restricting it this way is due to my need to practice the use of template classes. They will merely be used in a university seminar. I don't intend to publish any of them.
Thank you both for your answers! I'll give it a shot.