Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add compatibility with library structure without adding dependency on library?

I am currently writing a library that will sometimes be used alongside OpenCV. Because OpenCV defines a Point_ class that is commonly used in some of the contexts my library will be used in, I'd like to add the option to pass in Point_s as arguments to some of my functions. That said, OpenCV is a pretty heavy library and I'd very much prefer not to depend on it just to get access to it's Point_ class.

Defining my own Point_ identical Point_ class causes the expected multiple definition error.

I considered using a pre-processor macro to check if the OpenCV header containing Point_ has already been included and only define it if it has not been, but I'm concerned that if my libraries header is included first, the multiple definition error will return and this will make my library difficult to use for anyone other than myself.

Is there a way to provide a definition that will only be used if there is not definition anywhere else, and/or will be overridden if one does appear elsewhere?

like image 565
DaggerOfMesogrecia Avatar asked Jul 12 '18 14:07

DaggerOfMesogrecia


2 Answers

What you could do is define your library in terms of your point class and optionally generate conversions for the OpenCVlibrary types if present. Something like this:

#ifdef HAVE_OPENCV
#include <opencv2/opencv.hpp>
#endif

struct my_point
{
    double x;
    double y;

#ifdef HAVE_OPENCV
    my_point(cv::Point2d p): x(p.x), y(p.y) {}

    operator cv::Point2d() const { return {x, y}; }
#endif
};

my_point my_function(my_point p)
{
    return p;
}

int main()
{
    cv::Point2d p;

    // automatic conversions happen between OpenCV version
    // and your library's version
    cv::Point2d q = my_function(p);
}

Because the conversion operators are trivial, inline functions, the compiler will optimize them away completely leaving the code as if no conversion were happening at all.

Optionally (and preferably imo) you could make the conversions explicit which might make for safer code:

struct my_point
{
    double x;
    double y;

#ifdef HAVE_OPENCV
    // make these explicit
    explicit my_point(cv::Point2d p): x(p.x), y(p.y) {}

    explicit operator cv::Point2d() const { return {x, y}; }
#endif
};

my_point my_function(my_point p)
{
    return p;
}

int main()
{
    cv::Point2d p;

    // Now the library user needs to explicitly ask for
    // the conversions to take place
    cv::Point2d q = cv::Point2d(my_function(my_point(p)));
}
like image 108
Galik Avatar answered Nov 16 '22 22:11

Galik


One solution would be to handle this in your project build configuration: set a preprocessor definition (e.g. COMPILE_WITH_OPENCV) in your build system. If you're using CMake, it'll be something like

ADD_DEFINITIONS(-DCOMPILE_WITH_OPENCV)

And in the code:

#if defined COMPILE_WITH_OPENCV
#include "types.hpp" // openCV inlcude
#else
#include "my_types.hpp"  // your own Point_ definition
#endif
like image 1
nVxx Avatar answered Nov 16 '22 21:11

nVxx