2

To my current C++ project, I use an external library (1 big header) from a third party. This header provides multiple C like functions to drive hardware. To make it easier to use in C++, I wrote a C++ class to wrap those functions and hide this header with a pimpl implementation. Some parameters for those functions are defined by preprocessor directives #define in their main header. I would like to use the value of those parameters outside my wrapper class but without include this header.

I tried to use forward declared enum in my C++ class. But members of my enum are not available outside the source file where they are defined

external_lib.h

#define PARAM_A_VAL_0 0
#define PARAM_A_VAL_1 1
bool external_function_param_a(int param_a);

wrapper.h

class wrapper
{
    enum PARAM_A : int;
    ...
    bool SetParamA(wrapper::PARAM_A a);
}

wrapper.cpp

#include <wrapper.h>
#include <external_lib.h>
enum wrapper::PARAM_A: int
{
    VAL_0 = PARAM_A_VAL_0,
    VAL_1 = PARAM_A_VAL_1
};
bool wrapper SetParamA(wrapper::PARAM_A a)
{
     return external_function_param_a(a);
}

main.cpp

#include <wrapper.h>
int main()
{
    wrapper w;
    w.SetParamA(wrapper::PARAM_A::VAL_0);   
       // compilation error : VAL_0 not a member of wrapper::PARAM_A
}

Is there something wrong in my solution or this idea is just impossible? Is there a better solution. Create a lot of members to the class wrapper doesn't seem to be a good idea neither a switch on enum in all function members.

P1t_
  • 165
  • 1
  • 8
  • 1
    related: https://stackoverflow.com/questions/19074084/forward-declaring-enum-class-not-working – YSC Jan 03 '19 at 15:59
  • Ok. It answers why my solution doesn't work. But in this solution, the external header will be included everywhere this enum is used. – P1t_ Jan 03 '19 at 16:04

1 Answers1

3

If you must keep compile-time const-ness, you would not be able to avoid inclusion of external header, as explained in this Q&A.

If compile-time const-ness is not a requirement, you could separate declarations and definitions of wrapper::PARAM_A::VAL_NNN constants, like this:

Header:

struct wrapper {
    class PARAM_A {
        int val;
        PARAM_A(int val) : val(val) {}
        friend class ::wrapper;
    public:
        static const PARAM_A VAL_0;
        static const PARAM_A VAL_1;
    };
    bool SetParamA(wrapper::PARAM_A a);
};

Implementation:

const wrapper::PARAM_A wrapper::PARAM_A::VAL_0 = wrapper::PARAM_A(PARAM_A_VAL_0);
const wrapper::PARAM_A wrapper::PARAM_A::VAL_1 = wrapper::PARAM_A(PARAM_A_VAL_1);

bool wrapper::SetParamA(wrapper::PARAM_A a)
{
     return external_function_param_a(a.val);
}

Now the use of the API remains the same as in your example:

wrapper w;
w.SetParamA(wrapper::PARAM_A::VAL_0);
w.SetParamA(wrapper::PARAM_A::VAL_1);

Demo.

Note the way the class PARAM_A hides the int value: since it is no longer an enum, direct use in place of int is no longer possible, so the call to external_function_param_a needs to "unwrap" the value.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • One could add `operator int` to `PARAM_A` to overcome the "unwrap issue". Might be handy for the user if these constants are supposed to be used in other places as ints as well. Alternatively, if type safety is not important, one could get rid of the `PARAM_A` class and declare the constants as `static const int`. – sebrockm Jan 03 '19 at 16:57
  • @sebrockm I thought of adding a conversion to `int`, but in the end decided against it, because it would come dangerously close to defeating type safety, thus breaking the primary purpose of adding `wrapper::PARAM_A` type. I agree with you on your second point, though: if type safety is not a goal here, replacing `wrapper::PARAM_A` with `static const int` would be a great solution. – Sergey Kalinichenko Jan 03 '19 at 17:04