c++cenumsenum-classextern-c

Using a enum class from a c++ header in a c header


I am writing a c wrapper around a c++ library. In the c++ there are enum classes used as types for function arguments. How do I use theme correctly in the c header.

One ugly way would be to use int's in the c function and cast theme in the wrapper function to the enum type. But this gives the user of the c function no clue about the valid values, and it is really hard to check if the value is valid.

cpp header

namespace GPIO
{
    enum class Directions
    {
        UNKNOWN,
        OUT,
        IN,
        HARD_PWM
    };

    void setup(int channel, Directions direction, int initial = -1);
}

c wrapper header

    int setup(int channel, int direction, int initial);

c wrapper code

   int setup(int channel, int direction, int initial)
   {
        GPIO::setup(channel, static_cast<GPIO::Directions>(direction), initial);
        return 0;
    }

What would be a good way to give the user of the c functions the benefits of the enum classes in the c++ library. Because it is not my library, I would like to not change too much of the code in the library.

There would be the option to extract the enum classes to a different file and include it in the original header. But I don't know how to define it correctly, so I don't have to change the naming in the cpp library and still can use it in the c header.


Solution

  • You can not do it. It is impossible to use C++ features from C code. You are creating C wrapper for C++ function, why can not you create also C wrapper for enum? The only question is how to be sure that both enums have the same values. You can check it compile time after the small code change:

    cpp header:

    namespace GPIO
    {    
        enum class Directions
        {
            UNKNOWN,
            OUT,
            IN,
            HARD_PWM,
            SIZE
        };
    }
    

    c wrapper header:

    enum GPIO_Directions
    {
        GPIO_Directions_UNKNOWN,
        GPIO_Directions_OUT,
        GPIO_Directions_IN,
        GPIO_Directions_HARD_PWM,
        GPIO_Directions_SIZE
    };
    

    c wrapper code:

       int setup(int channel, GPIO_Direction direction, int initial)
       {
           static_assert(GPIO::Directions::SIZE == GPIO_Directions_SIZE, 
                           "c wrapper enum  must be equal to c++ enum");             
           GPIO::setup(channel, static_cast<GPIO::Directions>(direction), initial);
           return 0;
        }