5

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?

2 Answers2

3

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)));
}
Galik
  • 47,303
  • 4
  • 80
  • 117
  • I do like this approach, but it would like the other possible macro solution I mentioned and @nVxx's answer, require the user of my library to have knowledge of my library's special needs (to define the HAVE_OPENCV macro), which is what I am trying to avoid. – DaggerOfMesogrecia Jul 12 '18 at 15:24
1

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
nVxx
  • 661
  • 7
  • 20
  • That would work, but would like the other possible macro solution I mentioned, require the user of my library to have knowledge of my library's special needs, which is what I am trying to avoid. – DaggerOfMesogrecia Jul 12 '18 at 15:13
  • @DaggerOfMesogrecia, another trick would be to have your own header with the same header guard like the openCV one (i.e. `#ifndef OPENCV_CORE_TYPES_HPP`), this will help to write the rest of the code without any preprocessor branching, but this solution will still fail when OpenCV header is included after your library header. And I'm afraid there's no preprocessor/in-code solution to cover that. – nVxx Jul 12 '18 at 15:31