views:

108

answers:

3

Example:

I have a function that works with vectors:

double interpolate2d(const vector<double> & xvals, const vector<double> & yvals, double xv, double yv, const vector<vector<double> > &fvals) {
    int xhi, xlo, yhi, ylo;
    double xphi, yphi;
    bracketval(xvals,xv,xhi,xlo,xphi);
    bracketval(yvals,yv,yhi,ylo,yphi);
    return (fvals[xhi][yhi]*xphi+fvals[xlo][yhi]*(1.-xphi))*yphi + (fvals[xhi][ylo]*xphi+fvals[xlo][ylo]*(1.-xphi))*(1.-yphi);
}

But now I want to call it with boost::array elements for the first 2 arguments (same with bracketval()), if std::vector and boost::array were self-implemented, I would be able to derive both from a common base class (interface-like) enforcing an implementation of operator[], since both are library-provided, is there any way to cast/specify such a restriction?

I can always resort to plain c-arrays, but it's not very neat.

Edit: FWIW, here is the original bracketval implementation:

void bracketval(const vector<double> &vals, double v, int &hi, int &lo, double &prophi){
    hi=vals.size()-1;
    lo=0;
    while(abs(hi-lo)>1) {
        int md = (hi+lo)/2;
        if(vals[md]>v) hi=md; else lo=md;
    }
    if(vals[hi]!=vals[lo])
        prophi = (v-vals[lo])/(vals[hi]-vals[lo]);
    else
        prophi = 0.5;

}
A: 

There is no way to put type restrictions on template parameters. What you could is, is define your own interface and create adaptors for all types you want to support.

Space_C0wb0y
while technically true, there are ways to enforce template parameter types. For example, you can assign it to a base class, if, at compile time, this fails, it isn't a subclass of said base class and you've effectively put a restriction similar to extends in java.
roe
Do you know SFINAE or enable_if-paradigms?
phresnel
@roe: well, to test inheritance you want to use pointers. An *object* can be assignable to another type without being a subclass, for example if it has a conversion operator overload, or the type assigned to has a non-explicit 1-arg constructor, or the types are built-in and have a standard conversion: `float f = 'A';`
Steve Jessop
@Steve: I was merely making a point, although perhaps not waterproof. There are a lot more elaborate schemes as well. Not to mention the duck-typing aspect, as it won't compile unless it contains the required methods / operators / whatever. Although, I suppose whatever solution you chose, there's no way around the utterly miserable compile errors you'll get out of it, if there's something wrong.. :)
roe
+2  A: 

This works with std::vector, boost::array, built-in arrays an generally with anything that is indexable. I've also included a suggestion of how you should implement the bracketval function:

template<class Vec>
void bracketval(Vec const & xvals, double xv, int xhi, int xlo, double xphi)
{
}

template <class Vec, class VecOfVecs>
double interpolate2d(Vec const & xvals, Vec const & yvals, 
                     double xv, double yv,
                     VecOfVecs const & fvals)
{
    int xhi, xlo, yhi, ylo;
    double xphi, yphi;
    bracketval(xvals,xv,xhi,xlo,xphi);
    bracketval(yvals,yv,yhi,ylo,yphi);
    return (fvals[xhi][yhi]*xphi+fvals[xlo][yhi]*(1.-xphi))
             *yphi + (fvals[xhi][ylo]*xphi+fvals[xlo][ylo]
             *(1.-xphi))*(1.-yphi);
}

int main()
{
    {
        std::vector<double> v, w;
        std::vector<std::vector<double> > vv;
        interpolate2d(v, w, 1., 2., vv);
    }
    {
        boost::array<double, 4> v, w;
        boost::array<boost::array<double, 4>, 4> vv;
        interpolate2d(v, w, 1., 2., vv);
    }
    {
        double v[4], w[4];
        double vv[4][4];
        interpolate2d(v, w, 1., 2., vv);
    }    
}

You can even add an extra template parameter if you envision the possibility that the second vector could be of a different type that the first (e.g., the first a vector and the second a boost::array):

template <class VecX, class VecY, class VecOfVecs>
double interpolate2d(VecX const & xvals, VecY const & yvals, 
                     double xv, double yv,
                     VecOfVecs const & fvals)
Manuel
Much clearer than mine (even if mine had worked), and close to what I meant to post in the first place - I don't know what got into me :-)
anon
+1  A: 

While this is probably overkill for your specific problem, in general you can check wether template parameters implement a certain interface by explicitly checking wether certain members are provided and some expressions are valid.
Boosts concept check library gives you a clean way to do that, but the container checking classes it provides don't help you here because Boost.Array only supports a certain subset of the sequence requirements.

What you could do though if you need a clean way to put restrictions is modelling the requirements yourself, either utilizing Boosts utilities or a similar custom approach.

Georg Fritzsche