Templated Vector and Colour Maths library (Specialisation) - c++

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.

Related

Declare member function only for specific template instantiation of class

Is it possible to declare a member function only for specific template instantiations of a class? This is why I want to do it:
// Polynomial<N> is a polynomial of degree N
template<int N>
class Polynomial {
public:
//... various shared methods e.g...
double eval(double x) const;
Polynomial<N-1> derivative() const;
Polynomial<N+1> integralFrom(double x0) const;
// ... various shared operators etc.
double zero() const; // only want Polynomial<1> to support this
// only want Polynomial<2> and Polynomial<1> to support the following
// because the solutions rapidly become too difficult to implement
std::vector<double> zeros() const;
std::vector<double> stationaryPoints() const { return derivative().zeros();}
private:
std::array<double,2> coeffs;
}
My current workaround is to just throw an exception from Polynomial<N>::zeros() for N>2 but it would have been nice to detect the problem at compile-time.
You can also use std::enable_if to SFINAE away the zero function.
template< int I >
class Poly {
public:
template<int Ib = I, typename = std::enable_if_t<Ib == 1> >
double zero()
{
return 42;
}
};
int main()
{
Poly< 10 > does_not_compile;
does_not_compile.zero();
//Poly< 1 > compile;
//compile.zero();
}
You can use CRTP to implement zeros and zero in a base class that knows about the derived one.
Then conditionally derive from one that has zeros and/or zero, or not.
template<class P>
struct zeros { /* todo */ };
template<class P>
struct zero:zeros<P> { /* todo */ };
struct nozero {};
template<int N>
struxt Polynomial:
std::conditional_t<
(N==1),
zero<Polynomial<N>>,
std::conditional_t<
(N==2),
zeros<Polynomial<N>>,
nozero
>
>
{
// body
};
Your solution is template specialization, in this case, full specialization.
However, I think you would need to think about your design. Generally, it is not a good idea to define different interfaces for different cases because you are not taking advantage of the abstraction.
For example, think about your stationaPoints() function. This functions should not be available for Polynomial<2> because the derivative is a Polynomial<1> which does not have the zeros() function. Your solution is to add the zeros function to the Polynomial<1> in order to homogenize the interface.
For your case, I guess you would like a solution which includes a N-1 c-vector inside the polynomial type with the zeros and a zero(i) function to get them. Something like this:
template <int N>
class Polynomial {
double _coefs[N+1];
double _zeros[N];
public:
double zero(size_t i) const { assert(i<N); return _zeros[i]; }
// ...
};
In this case, you could decide the strategy to calculate de zeros, depending on your application: constructor?, adding a boolean to know if it has been calculated then it is calculated in the first call to zero, etc...
I guess this solution could be more interesting for you because if you prefer a c-vector to store the coeficients, you wouldn't like the vector based interface of your zeros() function, would you?

partial specialization with inheritance. Can I avoid inheritance?

I am writing a vector class and I would like it to have the following characteristics:
Use static allocation on the stack whenever possible (to avoid calling new for efficiency).
Be able to be instantiated from a pointer if the user prefers to provide a previously allocated array.
The class needs to be easily converted to a simple pointer. This allows to use previously written routines in C.
Find below this simple test problem with the solution I came up with. I use inheritance so Vector inherits from Vector_base which provides a common interface (pure virtual) for all vectors.
Then I define an empty class Vector that allows me then using partial specialization to have different storage schemes; static or dynamic.
The idea behind this is that I just want vector to be a C++ wrapper to the old-fashioned static array.
I like the implementation below. I'd like to keep the interface I came up with in main.
What I don't like is that sizeof(Vector3) = 32 when in C a vector of three doubles is 24 bytes. The reason for this is the extra 8 bytes of the virtual table.
My question: can I somehow come up with another design that would provide me with the same interface but the vector only has 24 bytes?
Summarizing:
I'd like have a Vector3 of 24 bytes, as in C.
I still want to have arbitrarily large vectors though (with <double,n>)
I'd like to keep the interface used in main().
Could I use a programming idiom like traits or polices for this? I am very new to those and I don't know if they could provide a solution.
Find my little test code below:
#include <iostream>
using namespace std;
#define TRACE0(a) cout << #a << endl; a;
#define TRACE1(a) cout << #a "=[" << a << "]" << endl;
enum alloc_type {Static,Dynamic};
template <class T>
class Vector_base{
public:
Vector_base(){}
virtual operator T*() = 0;
virtual T operator[](int i)const = 0;
virtual T& operator[](int i) = 0;
virtual int size() const = 0;
friend ostream& operator<<(ostream &os,const Vector_base& v){
for (int i=0; i<v.size(); i++)
cout << v[i] << endl;
return os;
}
};
// base template must be defined first
template <class T, int n,alloc_type flg=Static>
class Vector{};
//Specialization for static memory allocation.
template <class T, int n>
class Vector<T,n,Static>: public Vector_base<T>{
public:
T a[n];
public:
Vector() {
for (int i=0; i<n; i++) a[i] = 0;
}
int size()const{return n;}
operator T*(){return a;}
T operator[](int i)const {return a[i];}
T& operator[](int i){return a[i];}
};
//Specialization for dynamic memory allocation
template <class T,int n>
class Vector<T,n,Dynamic>: public Vector_base<T>{ //change for enum. flg=0 for static. flg=1 for dynamic. Static by default
public:
T* a;
public:
Vector():a(NULL){
}
Vector(T* data){ //uses data as its storage
a = data;
}
int size()const{return n;}
operator T*(){return a;}
T operator[](int i)const {return a[i];}
T& operator[](int i){return a[i];}
};
//C++11 typedefs to create more specialized three-dimensional vectors.
#if (__cplusplus>=201103L)
template <typename Scalar,alloc_type flg=Static>
using Vector3 = Vector<Scalar,3,flg>;
#else
#error A compiler with the C++2011 standard is required!
#endif
int main(){
cout << "Testing Vector3: " << endl;
//Vector<double,3> v3;
Vector3<double> v3;
TRACE0(cout << v3 << endl;);
TRACE1(sizeof(v3));
//Vector<double,3,Dynamic> v0(v3);
Vector3<double,Dynamic> v0(v3); //calls Vector<double,3,Dynamic>::Vector(double*) and uses the conversion operator on v3.
TRACE1(sizeof(v0));
TRACE1(sizeof(double*));
TRACE0(v3[1] = 2.1;);
TRACE0(cout << v0 << endl;);
return 0;
}
All the features you want are offered as Standard or can be plugged in to existing Standard extension points.
Use static allocation on the stack whenever possible (to avoid calling new for efficiency).
Meet std::array<T, N>. It's a C++ wrapper on a C array and presents all the same characteristics.
Be able to be instantiated from a pointer if the user prefers to provide a previously allocated array.
Meet Allocators. You can code an allocator that meets the requirement that gives back already allocated memory, then simply use std::vector. Such an allocator is under consideration for future Standards along with other allocator enhancements like polymorphic allocators.
The class needs to be easily converted to a simple pointer. This allows to use previously written routines in C.
Both std::vector and std::array offer this as a triviality.
If you want to offer this choice at runtime, consider boost::variant. Rolling your own discriminated union- not advised.
If I understand you correctly, something like LLVM's SmallVector seems to fit the bill. It has a template parameter declaring the maximum size you want allocated on the stack, and switches to heap memory only when it grows outside that range.
If it doesn't fit your interface directly, I'm sure looking at the implementation will be very useful towards writing something similar yourself.
You are talking about two policies for locating the data: either inline as a small-array optimization, or via indirection with a pointer to a dynamically allocated buffer.
There are two ways to make that policy choice: With static type information, or dynamically. The dynamic choice requires storage to indicate whether any particular vector uses the static or dynamic policy.
For a vector of doubles, you can perhaps use an illegal value in the first element (a NaN encoding) to indicate that the dynamic policy is in effect (the pointer needs to be stored overlapping the remaining elements, use a union for this).
But in other data types, all possible bit patterns are valid. For those you will require additional storage to select the policy. You might know for a particular problem that a particular bit isn't needed for the range of values, and can be used as a flag. But there's no general solution applicable to all data types.
You probably want to look at implementations of the "small string optimization". They are making the same tradeoff for improved locality of reference when the data is small enough to store directly inside the object, and also generally trying to avoid using mode space than necessary.
One thing is for sure. In order to avoid significantly increase in space requirements, you're going to need close coupling. No specialization, no inheritance, just one monolithic class that implements both policies.
Ok guys. It took me all day but this is the solution I came up with and it does exactly what I want. Please share your comments and suggestions to this solution.
Of course I didn't implement all methods I want. I only implemented two fake dot products to show how specific C implementations are chosen at compile time by use of templates.
The scheme is quite more complex than what I thought it would be. The basic concepts I'm using to accomplish my design requirements are:
the curiously recurring template pattern.
Partial specialization
Traits
Compile-time selection with templates (see how I decide what dot product implementation to use).
Again, thanks and please comment!! See code below
#include <iostream>
using namespace std;
#include <type_traits>
//C++11 typedefs to create more specialized three-dimensional vectors.
#if (__cplusplus<201103L)
#error A compiler with the C++2011 standard is required!
#endif
template<class T>
struct traits{};
#define TRACE0(a) cout << #a << endl; a;
#define TRACE1(a) cout << #a "=[" << a << "]" << endl;
enum {Dynamic = -1};
template<typename T,int n>
struct mem_model{
typedef T array_model[n];
};
//Specialization to Dynamic
template<typename T>
struct mem_model<T,Dynamic>{
typedef T* array_model;
};
template<class derived_vector>
struct Vector_base: public traits<derived_vector>{ //With traits<derived_vector> you can derive the compile time specifications for 'derived_vector'
typedef traits<derived_vector> derived;
typedef typename traits<derived_vector>::Scalar Scalar;
public:
inline int size()const{ //Calling derived class size in case a resize is done over a dynamic vector
return static_cast<const derived_vector*>(this)->size(); //derived_vector MUST have a member method size().
}
inline operator Scalar*(){return a;} //All vectors reduce to a Scalar*
inline bool IsStatic()const{return (n==Dynamic)? false: true;}
inline int SizeAtCompileTime()const{return n;} //-1 for dynamic vectors
protected:
using derived::n; //compile time size. n = Dynamic if vector is requested to be so by the user.
typename mem_model<Scalar,n>::array_model a; //All vectors have a Scalar* a. Either static or dynamic.
};
//Default static
template<typename Scalar,int n>
class Vector:public Vector_base<Vector<Scalar,n> >{ //Vector inherits main interface from Vector_base
public:
//Constructors
Vector(){
//do nothing for fast instantiation
}
Vector(const Scalar& x,const Scalar& y,const Scalar& z){
a[0] = x; a[1] = y; a[2] = z;
}
//
inline int size()const{return n;}
private:
using Vector_base<Vector<Scalar,n> >::a;
};
//Traits specialization for Vector. Put in an inner_implementation namespace
template<typename _Scalar,int _n>
struct traits<Vector<_Scalar,_n> >{
typedef _Scalar Scalar;
enum{
n = _n
};
};
double clib_dot_product_d(const int n,double* a,double* b){
double dot = 0.0;
for(int i=0;i<n;i++)
dot += a[i]*b[i];
return dot;
}
float clib_dot_product_f(const int n,float* a,float* b){
cout << "clib_dot_product_f" << endl;
return 1.0;
}
template<typename Scalar>
struct dot_product_selector{};
template<>
struct dot_product_selector<double>{
template<class derived1,class derived2>
static double dot_product(Vector_base<derived1> &a,Vector_base<derived2> &b){
return clib_dot_product_d(a.size(),a,b);
}
};
template<>
struct dot_product_selector<float>{
template<class derived1,class derived2>
static float dot_product(Vector_base<derived1> &a,Vector_base<derived2> &b){
return clib_dot_product_f(a.size(),a,b);
}
};
template<class derived1,class derived2>
typename Vector_base<derived1>::Scalar dot_product(Vector_base<derived1> &a,Vector_base<derived2> &b){
//run time assert checking the two sizes are the same!!
//Compile time (templates) check for the same Scalar type
static_assert( std::is_same<typename Vector_base<derived1>::Scalar,typename Vector_base<derived2>::Scalar>::value,"dot product requires both vectors to have the same Scalar type");
return dot_product_selector<typename Vector_base<derived1>::Scalar>::dot_product(a,b);
}
#if 0
template <typename Scalar,alloc_type flg=Static>
using Vector3 = Vector<Scalar,3,flg>;
#endif
int main(){
cout << "Testing Vector3: " << endl;
Vector<double,3> as;
Vector<double,Dynamic> ad;
TRACE1(sizeof(as));
TRACE1(sizeof(ad));
TRACE1(as.SizeAtCompileTime());
TRACE1(ad.SizeAtCompileTime());
Vector<double,3> u(1,2,3),v(-1,1,5);
Vector<float,3> uf,vf;
TRACE1(dot_product(u,v));
dot_product(uf,vf);
//dot_product(u,vf); //this triggers a compile time assertion using static_assert
return 0;
}
You could simplify the Vector template specialization to...
template <class T, std::size_t Size = -1>
class Vector {
// The statically allocated implementation
};
template <class T>
class Vector<T, -1> {
// The dynamically allocated implementation
};
The implementations could possibly be thin wrappers around std::vector and std::array.
EDIT: This avoid the magic constant...
template<typename T = void>
class Structure {};
template<typename T, std::size_t Size>
class Structure<T[Size]> {
T data[Size];
// The statically allocated implementation
};
template<typename T>
class Structure<T[]> {
T * pData;
public:
Structure(std::size_t size) : pData(new T[size]) {}
~Structure() { delete[] pData; }
// The dynamically allocated implementation
};
Instantiated like this...
Structure<int[]> heap(3);
Structure<int[3]> stack;
EDIT: Or use policies like so...
class AllocationPolicy {
protected:
static const std::size_t Size = 0;
};
template<std::size_t Size_>
class Static : AllocationPolicy {
protected:
static const std::size_t Size = Size_;
};
class Dynamic : AllocationPolicy {
protected:
static const std::size_t Size = 0;
};
template <typename T, typename TAllocationPolicy = Dynamic>
class Vector : TAllocationPolicy {
static_assert(!std::is_same<typename std::remove_cv<TAllocationPolicy>::type, AllocationPolicy>::value && std::is_base_of<AllocationPolicy, TAllocationPolicy>::value, "TAllocationPolicy must inherit from AllocationPolicy");
using TAllocationPolicy::Size;
public:
T data[Size];
};
template <typename T>
class Vector<T, Dynamic> : private Dynamic {
T * data;
public:
Vector(std::size_t size) : data(new T[size]) {}
~Vector() { delete [] data; }
};

Subclass a template class with operators

I'm trying to create classes for mathematical vectors in various dimensions, and since they have much in common I created a templated base class with the vectors size as the template parameter. I'm subclassing because I want different constructors (e.g. Vec2f(float x, float y), Vec3f(float x, float y, float z)) and additional functions like the cross product for 3 dimensional vectors.
My Problem: What should operator+ in the baseclass return? If it returns an instance of the baseclass then Vec3f + Vec3f returns Vecnf, but it should return Vec3f. Can this be achieved somehow?
Here is a code example:
template <size_t n>
class Vecnf {
public:
Vecnf operator+(Vecnf const & vec) const {
return Vecnf(*this) += vec;
}
Vecnf & operator+=(Vecnf const & vec) {
for (int i = 0; i < n; ++i) {
elements[i] += vec.elements[i];
}
return *this;
}
protected:
std::array<float, n> elements;
};
class Vec3f : public Vecnf<3> {
public:
Vec3f(float x = 0.0f, float y = 0.0f, float z = 0.0f);
Vec3f crossProd(Vec3f const & vec);
};
With this implementation, the following:
Vec3f a, b;
Vec3f c = a + b;
gives the compile time error
error: conversion from 'Vecnf<3u>' to non-scalar type 'Vec3f' requested
I'm using TDM GCC version 4.8.1 on Windows 8 Pro. I'm using c++11, so your solution can use it as well, but since I don't think it's crucial I haven't flagged the question with it. Thank you in advance :)
You could make the constructor a variadic template, thereby solving your first problem and eliminating the need to even use inheritance:
template <size_t n>
class Vecnf
{
std::array<float, n> elements;
public:
template <typename ... Args>
Vecnf(Args ... args):
elements {{static_cast<float>(args)...}}
{}
// other methods, operators etc...
};
Now you can make typedef's for the commonly used sizes if you like:
typedef Vecnf<3> Vec3f;
In my opinion, you could even improve this by adding another template parameter for the type you want to store in the array. It could default to float of course.
Also, it shouldn't be too hard to implement the cross-product in a generic way...
You can just define an operator+ on vec3f that does what you want it to. It can have a differing return type to vecnf's as long as it's a subtype of it and it will still override it.
Better solution is what #JorenHeit introduced; that actually is what you wanted, together with two typedefs. This solution is c++03 compatible though, and his isn't.

Dynamic data type choosing based on template

suppose I have an object like this:
class Spline {
public:
Spline(std::size_t const dim);
// Quite a few functions here. One of those:
vec operator()(double const t) const; // Returns vector of dimension d
}
Now, at most uses of this class, the dimension will already be determined at compile time, thus it would be a good idea (for performance reasons) to change the class like this:
template <std::size_t dim>
class Spline {
public:
Spline();
// Quite a few functions here. One of those:
vec::fixed<dim> operator()(double const t) const; // Returns vector of dimension d
}
(For those who wonder, vec and vec::fixed are objects defined by the armadillo linear algebra library). Now I would like to have both versions living in parallel, thus being able to choose the dimension at compile time as well as during runtime. In short, I would like to create the equivalent of vec::fixed<dim> as Spline::fixed<dim>, but without implementing all functions twice. Especially, I would have to choose the return type of all those functions depending on whether there is a template argument present or not.
Do you have any idea how I might accomplish this, especially thinking in terms of a clear and maintainable design? (In the hope that I made myself clear, which I am not totally sure about.)
Use a simple traits metastruct and specialize that.
template<std::size_t dim>
struct spline_return_traits{
typedef vec::fixed<dim> type;
};
template<>
struct spline_return_traits<0>{ // 0 is a special marker for runtime dimensions
typedef vec type;
};
template<std::size_t dim>
class Spline_impl{
typedef typename spline_return_traits<dim>::type spline_return;
public:
spline_return operator()(double const t) const;
// if <dim> is 0, then the dynamic vec will be chosen as the return type
// all your functions
};
class Spline : public Spline_impl<0>{ // default is dynamic
public:
template<int dim>
struct fixed : public Spline_impl<dim>{
};
};
Now you simple use that. :) Every operator, constructor and function of Spline_impl should be available in the subclasses. For the implementation of each function, you need to do some branching where it's a must to decide between runtime or fixed vec:
if(dim == 0){
// runtime specific stuff
}else{
// compile-time specific stuff
}
Use as:
Spline dynamic_spline;
Spline::fixed<10> fixed_10_spline;
Only problem being that the Spline class will be double the size of Spline_impl... :/ Lemme think if I can find a solution to that too.
Edit: If you don't want Spline to be double the size of Spline_impl, one possibility is to add a little verbosity and a typedef:
class Spline : public Spline_impl<0>{ // default is dynamic size
public:
template<std::size_t dim>
struct fixed{
typedef Spline_impl<dim> type;
};
};
And use as
Spline dynamic_spline;
typename Spline::fixed<10>::type fixed_10_spline;
If I understand your question correctly, you want a struct for compile time usage and runtime usage as well with preferably same name. In my opinion, you can declare the class as template and then specialize one of its instance (say size_t = 0xffffffff), which you may not be using. You can declare all your definitions for runtime usage in that instance.
For example,
template<std::size_t dim = ~0> // choose default dimension(0xffffffff) not to be used
class Spline {
public:
Spline () {}
vec::fixed<dim> operator () (double const t) const {}
};
template<>
class Spline<~0> { // specialize the default dimension for runtime use
public:
Spline (std::size_t const dim) {}
vec operator () (double const t) const {}
};
It can be used as below:
Spline<5> o5; // compile time dimensions
Spline<> o0(3); // run time dimensions (don't mention anything in template)
You can just overload it. Making a non-duplicate implementation, however, is a problem with no generic solution, unless you have more template magic that can do this.

Optional structural typing possibility in C++ or any other language?

In C++ how to tell compiler that Ogre::Vector3 IS_SAME_AS SomeOtherLIB::Vector3 ?
I feel that.. in languages like c++ which are not structural typed but there are cases when it makes sense.
Normally as game developer when working with 4+ libraries that provide sort or their own Vector3 implementation. The code is littered with ToOgre, ToThis, ToThat conversion function. Thats a lot of Float3 copying around which should not happen on first place.
Is in C++ or any other languages where we dont have to convert (copying) from one type to another which is essentially the samething. But any solution in C++ as most of the good gamedevs libs are for c/c++.
If you use templates you can define functions that take any type of argument as long as the necessary operations are defined on that type. Example:
class Foo { void quack() {} };
class Bar { void quack() {} };
class Baz {};
template<typename Duck>
void f(Duck d) {
d.quack();
}
int main() {
f(Foo()); // works
f(Bar()); // works
f(Baz()); // compile error because Baz does not have a quack method
return 0;
}
While it doesn't suit any situation, templates can give you "compile-time duck typing".
Lets say you have two vector types:
struct Vec3A {
float x, y, z;
};
struct Vec3B {
float p[3];
};
You can define function templates that hide the implementation how of to get the components:
template<class T> float get_x(const T&);
template<class T> float get_y(const T&);
template<class T> float get_z(const T&);
template<> float get_x<Vec3A>(const Vec3A& v) { return v.x; }
// ...
template<> float get_x<Vec3B>(const Vec3B& v) { return v.p[0]; }
// ...
With such helpers you can now write generic functions that work on both:
template<class T> float length(const T& t) {
return std::sqrt(std::pow(get_x(t), 2),
std::pow(get_y(t), 2),
std::pow(get_z(t), 2));
}
You can also continue by specializing utilities like length() for performance or other reasons, e.g. if a certain vector already has a member function providing you with the length:
template<> float length<Vec3C>(const Vec3C& v) {
return v.length();
}
If you are really sure in case of non-virtual structures, you can do a reinterpret_cast. However, it's better to:
do templated wrapper functions as shown by sepp2k
inherit from one of the vectors and add a conversion operator to the other vector
add a separate _cast function that does the conversion
Haxe is a highly portable language with completely optional structural subtyping:
typedef Vector3 = { x : double, y : double, z : double };
class FancyVector3 {
public var x : double, y : double, z : double;
function dot(Vector3 v) {
return x * v.x + y * v.y + z * v.z;
}
function length() {
return Math.sqrt(dot(this));
}
}
Not only is Vector3 an already usable structure, it also acts as a structural interface for other classes. Such typedef'd structs can specify function signatures as well as fields.
Haxe also has a CFFI for talking to C++ (although it still requires conversion methods), and bindings already exist for a few C++ game engines, as well as a variety of lower-level frameworks. Cross-platform engines written in pure Haxe are also being developed, targeting variously C++, Flash, and JS (both Canvas and WebGL).
This is probably not the solution you are looking for right now, but may become more interesting within a few years.