Design of similar typed classes - c++

I am designing classes to represent geometric objects such as vectors. I need to define methods such as addition, scalar multiplication, dot product and others. The vector coordinates can be integers or reals of different sizes, hence the need to replicate the classes corresponding to these different types.
E.g.
class intVector
{
int X, Y;
intVector& operator+=(const intVector& A) { … }
intVector& operator*=(int A) { … }
float Norm(); // Not int
};
class floatVector
{
float X, Y;
floatVector& operator+=(const floatVector& A) { … }
floatVector& operator*=(float A) { … }
float Norm(); // Would be double for a doubleVector
};
(I also need binary operators defined as functions rather than methods.)
I want to avoid/minimize code duplication, so using templates seems a natural approach. Anyway, I want my classes to appear as plain classes, not templated ones (one option is to derive from a templated class; another is to typedef class specializations).
In addition, there is a nasty constraint: not all methods make sense for all data types and shouldn't be declared at all in some classes, or there can be special cases with the types of certain arguments.
During my attempts, I faced numerous problems such as the need to add numerous explicit instantiations, difficulty to avoid the members that don't make sense, cast issues between the base/derived classes… making the whole design painful. all in all, I spend writing more code with templates than without !
Have you experienced similar class designs ? Is there a classical way to solve this ?

Templates are the right way to handle this. What you can do is add overloads for the different functions that need to behave differently and use SFINAE to constrain them to the types they are needed for. Using a template we can combine both classes into a generic Vector class and then use a type alias to get concrete names for the different types. That would look like
template<typename T>
class Vector
{
T X, Y;
Vector& operator+=(const Vector& A) { … }
Vector& operator*=(T A) { … }
template<typename U = T, std::enable_if_t<std::is_integral_v<U>, bool> = true>
correct_size_floating_point_type<U> Norm() { integer code }
template<typename U = T, std::enable_if_t<std::is_floating_point_v<U>, bool> = true>
U Norm() { floating point code }
};
using intVector = Vector<int>;
using floatVector = Vector<float>;
Where correct_size_floating_point_type is a template type that returns a correctly sized floating point type for the supplied integer type.

Related

Why are std::vector and std::string's comparison operators defined as template functions?

A little overview. I'm writing a class template that provides a strong typedef; by strong typedef I am contrasting with a regular typedef which just declares an alias. To give an idea:
using EmployeeId = StrongTypedef<int>;
Now, there are different schools of thought on strong typedefs and implicit conversions. One of these schools says: not every integer is an EmployeeId, but every EmployeeId is an integer, so you should allow implicit conversions from EmployeeId to integer. And you can implement this, and write things like:
EmployeeId x(4);
assert(x == 4);
This works because x gets implicitly converted to an integer, and then integer equality comparison is used. So far, so good. Now, I want to do this with a vector of integers:
using EmployeeScores = StrongTypedef<std::vector<int>>;
So I can do things like this:
std::vector<int> v1{1,2};
EmployeeScores e(v1);
std::vector<int> v2(e); // implicit conversion
assert(v1 == v2);
But I still can't do this:
assert(v1 == e);
The reason this doesn't work is because of how std::vector defines its equality check, basically (modulo standardese):
template <class T, class A>
bool operator==(const vector<T,A> & v1, const vector<T,A> & v2) {
...
}
This is a function template; because it gets discarded in an earlier phase of lookup it will not allow a type that converts implicitly to vector to be compared.
A different way to define equality would be like this:
template <class T, class A = std::allocator<T>>
class vector {
... // body
friend bool operator==(const vector & v1, const vector & v2) {
...
}
} // end of class vector
In this second case, the equality operator is not a function template, it's just a regular function that's generated along with the class, similar to a member function. This is an unusual case enabled by the friend keyword.
The question (sorry the background was so long), is why doesn't std::vector use the second form instead of the first? This makes vector behave more like primitive types, and as you can clearly see it helps with my use case. This behavior is even more surprising with string since it's easy to forget that string is just a typedef of a class template.
Two things I've considered: first, some may think that because the friend function gets generated with the class, this will cause a hard failure if the contained type of the vector does not support equality comparison. This is not the case; like member functions of template classes, they aren't generated if unused. Second, in the more general case, free functions have the advantage that they don't need to be defined in the same header as the class, which can have advantages. But this clearly isn't utilized here.
So, what gives? Is there a good reason for this, or was it just a sub-optimal choice?
Edit: I wrote a quick example that demonstrates two things: both that implicit conversion works as desired with the friend approach, and that no hard failures are caused if the templated type doesn't meet the requirements of the equality operator (obviously, assuming the equality operator is not used in that case). Edit: improved to contrast with the first approach: http://coliru.stacked-crooked.com/a/6f8910945f4ed346.
The techique you describe (what I call Koenig operators) was not known, at least not widely, at the point vector was designed and originally specified.
Changing it now would require more care than using it originally, and more justification.
As a guess, today Koenig operators would be used in place of template operators.
EDIT: After I re-read my explanation and influenced by a few comments around, I'm convinced my original reasoning is not compelling indeed. My answer essentially attempted to argue that although a value x could be implicitly converted to a value y of a different type, an "automagically" equality comparison between the two might not necessarily be expected. For contextualization, I'm still leaving here the code I used as an example.
struct B {};
template <class T>
struct A {
A() {}
A(B) {}
friend bool operator==(const A<T>&, const A<T>&) { return false; }
};
// The template version wouldn't allow this to happen.
// template <class T>
// bool operator==(const A<T>&, const A<T>&) { return false; }
int main() {
A<B> x;
B y;
if (x == y) {} //compiles fine
return 0;
}

Templated Vector and Colour Maths library (Specialisation)

I have created a maths library that operates via templates, it allows the user to specify the size and type of the array within a class which is then used to create a maths vector of any dimension up to four. As soon as I went to create a colour class, it struck me how similar the vector and colour class are. Is there anyway in which I could reduce code reuse and use some form of inheritance or specialisation to separate:
Specific functionality (ie vector3 does not have a setXYZW() function, instead only a setXYZ()) to the dimension of which it can only be used in.
Colour class and vector class can both (in terms of array data member) be of size ranging from 1 to 4 and the both share the same operators, but differ in their use in some circumstances such as a multiply vector differs from a multiply colour.
My knowledge of templates is not that good, so I would very much appreciate if anyone can show me the best solution to such a situation?
template < std::size_t N = 3, typename T = float >
class Vector
{
typedef T Degree, Radian;
private:
T m_vecEntry[N];
public:
// arithmetic operations
Vector operator + (const Vector & _vector) const;
Vector operator - (const Vector & _vector) const;
Vector operator * (const Vector & _vector) const;
Vector operator * (float _val) const;
};
template < std::size_t N = 4, typename T = float >
class Colour
{
private:
T m_colEntry[N];
public:
// arithmetic operations
Colour operator + (const Colour& _colour) const;
Colour operator - (const Colour& _colour) const;
Colour operator * (const Colour& _colour) const;
Colour operator * (float _val) const;
};
Your classes have a fair amount of duplicated code, it is advisable that you do something about it. A possible solution follows.
First, you take the common functionality to a base class:
template <class Derived, std::size_t N, typename T>
class VectorBase
{
protected:
VectorBase() {} // Prevent instantiation of base
Derived operator + (const Derived & _vector) const {
std::cout << "Base addition\n";
return Derived();
}
Derived operator * (T _val) const {
std::cout << "Base scalar multiplication\n";
return Derived();
}
T m_components[N];
};
Then you derive from it your Vector and Colour classes. In each derived class you use using Base::operation; to state explicitly that the corresponsing operation from the base class makes sense in the derived class.
For operations that don't make sense in the derived class you provide an alternative definition or not provide it at all (it will not be accessible since you didn't write using).
You can also add operations that were not in the base class, like Vector::norm:
template < std::size_t N = 3, typename T = float >
class Vector : VectorBase<Vector<N, T>, N, T>
{
typedef VectorBase<Vector<N, T>, N, T> Base;
typedef T Degree, Radian;
public:
using Base::operator+; // Default implementation is valid
using Base::operator*; // Default implementation is valid
T norm() const { // Not present in base class
return T();
}
};
template < std::size_t N = 4, typename T = float >
class Colour : VectorBase<Colour<N, T>, N, T>
{
typedef VectorBase<Colour<N, T>, N, T> Base;
public:
using Base::operator+; // Default implementation is valid
Colour operator * (T _val) const { // Redefines version in base class
std::cout << "Colour scalar multiplication\n";
return Colour();
}
};
The only trick in this code is that I've used the CRTP to make base class operations work with derived types.
Here is a little test program:
int main()
{
Vector<> va, vb;
va + vb;
va.norm();
va * 3.0;
Colour<> ca, cb;
ca + cb;
ca * 3.0f;
}
It prints:
Base addition
Base scalar multiplication
Base addition
Colour scalar multiplication
Ultimately the compiler will only create the parts of the template specialization it determines you are going to use. So it in affect will do the optimization for you e.g. not creating an unused method and so on.
So you may just want to consider making normal pre-processor macros to wrap the slight tweaks per template.
But obviously if you want to make some specializations you can do that too, but you'll still end up duplicating lines of code as it were ;)
A lot of graphic engines keep the two separate for precisely the reasons you mentioned. While the structure of the data is equal both require different semantics for operations on the data. This also has the added benefit of more meaningful function names (setX vs setRed) but means code duplication.
Your implementation is just a wrapper around fixed size arrays. You could move the data and shared functionality in a (possible abstract) base class and provide the specific functionality in child classes.
Another way would be to treat your vector and colour classes as decorators to an array wrapper. Write or use a wrapper around arrays and combine it with vector/color functionality through composition.

when is better to use c++ template?

right now i am learning C++, and now I know the basic concept of template,
which act just like a generic type,
and i found almost every c++ program used template,
So i really want to know when are we supposed to use template ?
Can someone conclude your experience for me about c++ template ?
When will you consider to use template ?
Supplement:
if we defined such function
template <class myType>
myType GetMax (myType a, myType b) {
return (a>b?a:b);
}
but we want to pass a object(self-defined class) for comparison, how can we implement ?
Supplement2:
in the answer below, someone have wrote this sample code
template <class myType>
const myType& GetMax (const myType& a, const myType& b) {
return (a<b?b:a);
}
template <class myType, class Compare>
const myType& GetMax (const myType& a, const myType& b, Compare compare) {
return (compare(a,b)?b:a);
}
is this correct ? can we just pass a function name as a parameter of class myType ?
Re: supplement. If you want to pass a comparison function, you could provide another overload:
template <class myType>
const myType& GetMax (const myType& a, const myType& b) {
return (a<b?b:a);
}
template <class myType, class Compare>
const myType& GetMax (const myType& a, const myType& b, Compare compare) {
return (compare(a,b)?b:a);
}
Samle usage: to compare C-style strings:
bool c_strings_less(const char* a, const char* b)
{
return std::strcmp(a, b) < 0; //is a less than b
}
const char* greater = GetMax("hello", "world", c_strings_less);
This is how the std::max algorithm works. (I also made a few modifications, e.g it is customary in C++ that predicates define "less-than" comparison.)
Or if you asked, how GetMax would work for arbitrary user-defined types, then those must overload operator> or your function would result in a compile error.
G'day,
Simple answer is when you want the behaviour to remain the same independent of the type being used to instantiate the class.
So a stack of ints will behave in the same way as a stack of floats will behave as a stack of MyClass objects.
Inheritance and base classes are used when you want to allow specialisation of the behaviour.
So say you have a base class called Animal and it has a member function called makeSound(). You have no idea which sound every animal will make so you make the makeSound member function a virtual function. In fact, because there is no default sound for all animals you have no idea what to have as default behaviour so you would declare this member function as a pure virtual function.
This then tells anyone making an instance of a derived class, for example a Lion class, that they must provide an implementation the makeSound member function which will provide a roar in some way.
Edit: I forgot to add that this is one of the articles in Scott Meyers's excellent book "Effective C++" (sanitised Amazon link) which I highly recommend.
HTH
cheers,
Basically when you want to create a generic class that can handle the solution for multiple types of classes, without having to have a parent-class for all the classes you want to support.
You can just give the class along with which you want to work with (best example would be a container, which can store any type that you pass along with the creation)
//----- the container
template <class T>
class Stack
{
public:
T* stackPtr;
}
//----- example
void main()
{
typedef Stack<float> FloatStack;
typedef Stack<int> IntStack;
}
Now you can store floats and ints with the same class without having to write a specific class for each type.
Short answer: if there is no use for it: don't.
If it seems to solve a problem (code reuse on different types,...), first implement and debug without templates and then add template parameters.
Before STL/boost, they were nice to make containers.
In the example you provided, everything is OK as long as operator > is defined for the data type whose instances you're comparing.
For example, if you define the following class:
class fraction
{
private:
int _num, _den;
public:
fraction(int num, int den)
{
if (den >= 0)
{
_num = num;
_den = den;
}
else
{
_num = -num;
_den = -den;
}
}
fraction(const fraction &f)
{
_num = f._num;
_den = f._den;
}
bool operator > (const fraction &f) const
{
return (_num * f._den) > (f._num * _den);
}
bool operator == (const fraction &f) const
{
return (_num * f._den) == (f._num * _den);
}
};
Then you can use your template function with instances of this class.
int main(int argc, char* argv[])
{
fraction a(1,2); // 0.5
fraction b(3,4); // 0.75
assert(GetMax/*<fraction>*/(a,b) == a);
return 0;
}
When you need to parameterize concept represented by a class.
For example, if you have a class that represent a way to manage a type of object
class MyThingManager
{
void add( MyThing& mything );
//...
};
...maybe you need later to use exactly the same behaviour in a new type but managing a different type. Then you have the choice to use copy/paste/replace --that would lead hell opening under your feet immediately-- or make your class have a type to manage as parametter :
template< class ThingType >
class ThingManager
{
void add( ThingType& thing );
//...
};
That way you don't duplicate code.
Another concern is when you want some function call to be compatible with any parameter that have the required semantic :
template< class MyType >
void addPi( MyType& value )
{
value += PI;
}
That way you (again) don't have to duplicate code for each types possible in parametters.
It's not called "generic programming" for nothing.
Those are simple cases, but more complex cases exists, when you want to do some meta-programming. If you want to go there, please read at least one book before writing hell code. I recommand "C++ Template Meta-Programming" for that and the excellent "Modern C++ Design" book for more advanced template usage like Policy pattern ans other well known.
Answering the second question(
but we want to pass a object(self-defined class) for comparison, how can we implement?)
If you want to use your own class in a template function using the
operator >.
Your class need only to define this operator or function.
The important part is that your class need to define the same
the operator or function the template uses.
/Tobias
if you dont know the type of your variable or you want to do same thing for many types of variables, you can use template...
if you want to add 2 int, you want to get an int for return
if you want to add 2 double, you want to get an double for return
so you use template for this..
Template provide the way to parametrize on KNOWN AT COMPILE TIME quantities. Note that it can be a type (std::vector will contain only integers) but they can also be values:
template <int N, typename T > class MyType
is templatized both on an integer and a type, and MyType<2, int> will be a different type from MyType<3, int>.
Furthermore, templates allow for Template Metaprogramming: that is the compiler executes a program at compile time. There is a fascinating example by Erwin Unruh for computing primes at compile time.
Look at http://ubiety.uwaterloo.ca/~tveldhui/papers/priority.html for a small bit of history.
It's important to note that it's perfectly alright to not write your own templates. If you're not sure why you might need them, then you probably don't need them. Templates are a very powerful tool, but they are not always the best solution.
On any common development platform, the standard library provides a high-quality implementation of many of the old-school, traditional uses of templates. Using the standard library classes and functions doesn't require writing new templates. For instance, it provides std::max(), which is the same as your example.

Unknown return type of template functions, code repetition when using decltype

In my job, there are several template mathematical classes (e.g matrix).
An object can be implemented using either floats or doubles (or other numerical types but for this matter, it doesn't really matter).
A double object can only interact with another double object. For this matter the function convert() was implemented for various types, with an implementation similar to this:
Matrix<T2> convert(const Matrix<T1>& m, T2 dummy) {
// create a matrix with type T2 and cast m values into it
// retMatrix(i, j) = (T2)m(i,j)
}
You would call it with:
auto floatMatrix = convert(doubleMatrix, 0.f);
Or the slightly more verbose:
auto floatMatrix = convert(doubleMatrix, float());
I want to add a function like the one below that will enable a cleaner (IMHO) way to call these functions
template <typename T, typename S>
auto convert(S&& s) -> decltype(convert(s, T())) {
return convert(s, T());
}
Now they can be called using:
auto floatMatrix = convert<float>(doubleMatrix);
My question is that my function signature is pretty awkward, I need to repeat the convert(s, T()) both in the decltype and in the actual function body
How do I overcome this?
thanks
edit:
currently, we are not using c++14
edit #2:
the Matrix class was just an example, there are quite a few relevant classes that have the convert() function implemented for them. Each of them already "specialized" like someone suggested in an answer below (deleted meanwhile). I would like to adjust the way convert() is called without re implementing everything
edit #3:
supported types are obviously other than only float and double. please treat the example I gave as an example and not the actual problem I'm trying to solve
the "dummy" functions are already implemented, I was trying to make it work with minimal effort, instead of refactoring 30 functions and all usages
I don't think the question is so far fetched considering cpp14 allows to just remove the -> decltype() thingy...
A little confusing why the need for templates in the first place instead of function overloading:
Matrix<double> convert(const Matrix<float>& m) {
// ...
}
Matrix<float> convert(const Matrix<double>& m) {
// ...
}
float->float and double->double don't seem like meaningful operations that need to be preserved so actually making that a compiler error seems beneficial (whereas the template mechanism might actually succeed and just create an unnecessary copy).
Also the need for the dummy parameter in the first place is confusing without a more complete example.
If you're set on templates (e.g. types go beyond just these two):
template <typename T2, typename T1>
Matrix<T2> convert(const Matrix<T1>& m) {
}
If you're trying to write 1 single generic conversion function across all your other conversion functions you have no way of simplifying what you wrote until C++14 (I mean there are other ways to write it but it seems unlikely to be simpler).
One option might be helper classes that know the conversion type from Matrix for T to Matrix, but they are no prettier than the decltype statement, which is readable and local to the code.
Could Matrix derive from a base class that knows how to generate Matrix from T? Perhaps as a member so you can write:
class MatrixBase
{
public:
template <class T> class To
{ typedef Matrix<T> To; };
};
class Matrix<int>:public MatrixBase {
// ...
};
All this just to write: -> S::To<T>::To
As you say, come the C++14 revolution you can do the fully automatic return type thing.

Design a class that can be convertible to/from other libraries

I wrote a small self-contained library (depends only on the C++ standard library) that has its own built-in 3D vector class:
namespace mylibrary {
struct Vector {
double x, y, z;
// and constructors
// like:
Vector(double x, double y, double z);
// and operators
};
}
It's supposed to interact with other code that produces/uses 3D vectors.
Now, assume some other library, which has:
namespace otherlibrary {
struct Vector3 {
// some different definition
// And is still able to construct from 3 values
Vector3(double x, double y, double z);
};
doSomething(const Vector3& point); // do something with the point
}
This other library could be the plugin API for a 3D modelling tool, or a 3D engine. It also has the concept for a 3D vector, but it's of course a different type than my library's vector, even though the semantics are identical. Think of Python's duck typing: the type doesn't matter as long as it behaves in the expected way.
Question:
What mechanism could I use to make my library's Vector be used conveniently as an argument for otherlibrary::doSomething()?
That is, being able to write this:
otherlibrary::doSomething( mylibrary::Vector(...) );
I can certainly build my Vector class to have a templated constructor that accepts any type T with "x, y, z" members, or with operator[], so it can consume almost anything that makes sense to interpret as a 3D vector. Would it be possible to do it the other way around?
EDIT:
Of course, I could just make it dependent on another library, then I could just reuse the other library's 3D vector abstraction. This is not reasonable, as my library is generic, it makes no sense to, say use Eigen::Vector3d for my vector, as it could then be used in an environment that doesn't use Eigen.
Best answer:
Based on Neil Kirk's answer:
struct Vector {
using value_type = double;
template<class T,
class = typename enable_if<
is_constructible<T, value_type,value_type,value_type>::value
>::type>
operator T() const
{
return T{x, y, z};
}
};
The enable_if i used to resolve ambiguities when multiple overloads functions and operators are available; Eigen is one actual case where it is needed.
Yes add conversion operator to your Vector class.
operator otherlibrary::Vector3() const
{
return otherlibrary::Vector3(x, y, z);
}
But it means your vector will now depend on the other library..
To avoid dependency, there is no way to do exactly what you are asking. Alternative suggestion is a convert function such as the following, which makes a couple of assumptions about the vector types.
template<class T, U>
T ConvertVector3(const U& v)
{
return T(v.x, v.y, v.z);
}
otherlibrary::doSomething(ConvertVector3<otherlibrary::Vector3>(mylibrary::Vector(x, y, z)));
Very verbose though :(
Experimental!! I didn't try this and have no idea if it works. Concern: your vector could convert to any class that takes 3 constructor arguements, even if it doesn't make sense
template<class T>
operator T() const
{
return T(x, y, z);
}
There is seldom a reason to define your own vector3 type, and this is a serious downside. Even if you do something clever with templates, it can conflict with similar "cleverness" in other libraries.
Define your operators as free functions, not members, and use std::array instead. If you really must have your own class, define a to_array() function returning the standard type. Any sane library can convert from that, even by using array::data() to treat it as a C array.
(Protip: you can reinterpret_cast a C-style array to std::array & reference and back, to avoid copying data.)

Resources