1

Background

I am working on a platform independent (Linux, macOS and Windows) scientific imaging application which implements various specialist cameras and each of these cameras has a manufacturer provided SDK. I am currently implementing a selection of new cameras that are manufactured by a single company but are branded by other manufactures with separate SDKs.

Aside form minor differences in the SDK function names, the public interfaces are identical. That is to say, everything is the same (function return type and signature etc). The only difference is the start of the function name.

Example of the public interface of the SDKs

int company_1_count_cameras();
bool company_1_init_camera(...);
bool company_1_connect_camera(...);

And:

int company_2_count_cameras();
bool company_2_init_camera(...);
bool company_2_connect_camera(...);

I would like to be able to use one implementation for all the OEM cameras but take into account the function name differences. I have experimented with using function pointers in preprocessor defines and this partly works. So far, I have done the following:

I have placed the following into the include file:

#define FP( func ) company_2 ## func

And in the implementation, I have done:

int count = FP(count());

However, I am unsure of how to do this so that I can compile my project to support all the different cameras. Can anybody offer any suggestions on the best way to achieve this?

Many thanks Amanda

Amanda
  • 321
  • 2
  • 12
  • 4
    First of all pick one language. C and C++ are different languages and will have different solutions. The second, you should learn OOP, interfaces and interface implementations, this is what you apply for your task. – 273K Aug 01 '21 at 16:40

2 Answers2

7

A more formal C++ way is to define an interface definition class:

struct company_interface {
   int (*count_cameras)();
   bool (*init_camera)(...);
   bool (*connect_camera)(...);
};

And then instantiate a separate instance for each company:

const company_interface company_1{
   &company_1_count_cameras,
   &company_1_init_camera,
   &company_1_connect_camera
};

const company_interface company_2{
   &company_2_count_cameras,
   &company_2_init_camera,
   &company_2_connect_camera
};

At this point there are many different possible design decisions, ranging anywhere from passing a const company_interface & wherever something needs to do something with the camera, or making company_interface itself a big class that implements high level functionality.

The advantage of this approach is that the actual camera-specific API is needed only in the translation unit that defines the instances of the interface definition class. Everything else needs only the declaration of the interface class, and it will invoke the camera APIs directly through function pointers, without the need to include the declaration of every camera API, in every translation unit that needs to call one.

Plus, it is now trivial to mock up a unit-testing framework that simulates a camera API.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • Your answer makes sense and I've been able to write a small test program to prove that it works. However, I was a little too quick at saying that the function signatures were the same. There are in fact some differences. For example, some of the functions from the APIs require a camera identification handle of a different type. Is it possible to adapt this solution use different signatures or is another approach needed? – Amanda Aug 01 '21 at 22:33
  • Yes, many different approaches are possible, but there is no one-size-fits-all, cookie-cutter, solution to every possible situation. It all depends on the specific details. – Sam Varshavchik Aug 01 '21 at 23:02
0

You can make your FP macro dependent on a platform-specifc macro like so:

#if defined _WIN32
# define FP(...) win32_##__VA_ARGS__
#elif defined __linux__
# define FP(...) linux_##__VA_ARGS__
#elif defined __APPLE__
# define FP(...) apple_##__VA_ARGS__
#else
 static_assert(false, "Unsupported configuration");
#endif

See more platform specific macros here.

Note that this has nothing to do with function pointers.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93