Trouble with boost::tuple in boost::unordered_map within a templated class

379 views Asked by At

I've written a method which automatically interpolates an expensive 2D function in C++. I'm now trying to allow the class to accept a function pointer so that any function can be interpolated. To do this, it appears I need a templated class so that I can template it for each object which it needs to evaluate the function pointer upon. That part is not so bad after I realized I need to define the class entirely in the header so that the linker can template out the class for each object needed. Now the rub.

Within the class I use boost::unordered_map to store function evaluations so that I don't unnecessarily call the function. During the interpolation I refine a grid so that it sufficiently describes it (based upon its curvature). I'm locally subdividing the mesh, so that if my original points were at x=0, .5, 1, the next set might be x=0, .25, .5, 1, where I would only need to evaluate at x = .25 for the second pass. That's working on its own with a hard coded function, in place of the dynamic function pointer.

The trouble I am having is in defining the necessary operator and hash_value functions for the boost::tuple. If I put it in the header they are defined multiple times (for each include of the header). If I try and compile it as an object and link it in, the linker fails to find the definitions. The two definitions I need to reference in the class:

bool operator==(const BoostTuple2D &a, const BoostTuple2D &b)
{
    return a.tuple.get<0>() == b.tuple.get<0>() &&
            a.tuple.get<1>() == b.tuple.get<1>();
}

std::size_t hash_value(const BoostTuple2D &e)
{
    std::size_t seed = 0;
    boost::hash_combine(seed, e.tuple.get<0>());
    boost::hash_combine(seed, e.tuple.get<1>());
    return seed;
}

In my header I have a struct and typedef:

struct BoostTuple2D {
    BoostTuple2D(double x1, double x2)
        : tuple(x1, x2) {}
    boost::tuples::tuple<double, double> tuple;
};

typedef boost::unordered_map< BoostTuple2D, double > BoostTuple2DMap;

Which is just above my templated class, with ommitions:

template<class F>
class Interpolate {
public:
    class Evaluate { 
    // this class uses the map to cache evaluations of the dynamic pointer
        }

    Interpolate (double (F::*f)(double, double), F & obj, [...]) : f(f), object(obj), ... {};

private:
    // members
};

How can I make the operator== and hash_value methods available to the class without defining them multiple times? I am guarding the header file. I am a c++ newbee, so hopefully its something simple I'm not getting. Thanks!

1

There are 1 answers

2
Dave S On BEST ANSWER

In the case of non-template methods in a header, you will need to preceed them with the keyword 'inline'. While there is no guarantee that the function will be inlined (it is merely a hint in this case), it does require the linker allow multiple definitions.

inline bool operator==(const BoostTuple2D &a, const BoostTuple2D &b)
{
    return a.tuple.get<0>() == b.tuple.get<0>() &&
            a.tuple.get<1>() == b.tuple.get<1>();
}

std::size_t hash_value(const BoostTuple2D &e)
{
    std::size_t seed = 0;
    boost::hash_combine(seed, e.tuple.get<0>());
    boost::hash_combine(seed, e.tuple.get<1>());
    return seed;
}

If you're having problem placing them in their own source file, but leaving the declaration in the hedaer, there might be an issue with the namespace you're putting them in. I would have to see that version of the code to help.

As a note, tuples should already have an operator== defined, so you can use that instead of comparing element by element yourself (the default already does that).