Как обернуть c ++ std :: shared_ptr в файл заголовка оболочки, чтобы его можно было вызывать из c? - PullRequest
0 голосов
/ 24 сентября 2019

Я пишу небольшой Wrapper API, чтобы я мог вызвать C++ код (классы / функции) из C.У меня проблема в том, что одна из моих C++ функций инициализируется в моем заголовке оболочки с "shared_ptr".

ClassName *ClassName _new(std::shared_ptr<Lib::Instance> p_Instance);

Так что, как вы можете видеть, файл оболочки заполнен в стиле C ++.Это плохо, потому что файл Wrapper should be readable by C AND C++.

Это мой файл Wrapper.h:

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

typedef struct ClassName ClassName;

ClassName *ClassName_new(std::shared_ptr<Lib::Instance> p_Instance);

void ClassName_setValue(ClassName* t, double p_value);

void ClassName_delete(ClassName* t);

#ifdef __cplusplus
}
#endif /* __cplusplus */

, а это мой файл Wrapper.cpp:

#include "Wrapper.h"
#include "ClassName.h"

extern "C"{

ClassName* ClassName_new(std::shared_ptr<Lib::Instance> p_Instance){
       return new ClassName(p_Instance);
}

void ClassName_setValue(ClassName* t, double p_value){
        t->setValue(p_value);
}

void ClassName_delete(ClassName* t){
        delete t;
}
}

И это часть моего основного.Заголовок файла cpp:

class ClassName: public SDCLib::Util::Task {
public:
   ClassName(std::shared_ptr<Lib::Instance> p_Instance);
   virtual ~ClassName();
   void setValue(double p_value);
   ...

.Cpp:

ClassName::ClassName(std::shared_ptr<Lib::Instance> p_Instance) ...
...
   void ClassName::setValue(double p_value){
      doSomething()
   }
...

Мне не разрешено изменять структуру основного файла c ++, где я использую ClassName(std::shared_ptr<Lib::Instance> p_Instance);

У вас есть идеи, как я могу решить эту проблему?Может быть, написание второго Wrapper?

Редактировать: Вот ошибка Терминала:

Wrapper.h:21:45: error: expected ‘)’ before ‘:’ token
 ClassName *ClassName_new(std::shared_ptr<Lib::Instance> p_Instance);
                             ^

Ответы [ 3 ]

1 голос
/ 24 сентября 2019

Я бы предложил встроить счетчик ссылок в объект и использовать boost::intrusive_ptr с ним.Таким образом, вы можете передать простой указатель на функции C, и эти функции C все еще могут управлять временем жизни объекта, напрямую вызывая стиль C addref/release для него.

1 голос
/ 24 сентября 2019

Эта функция не может быть использована в C, поэтому вы можете использовать препроцессор для удаления объявления так же, как вы использовали с extern "C":

// Wrapper.h
#ifdef __cplusplus
ClassName *ClassName_new(std::shared_ptr<Lib::Instance> p_Instance);
#endif

Хотя, эта обертка не должнадля использования в C ++ чем-либо другим, кроме Wrapper.cpp, тогда перенос объявления в Wrapper.cpp может быть лучшим вариантом.


Если вам нужен способ вызова ClassName_new из C, япредложил бы отклониться от общего указателя.Но вы могли бы заставить его работать с непрозрачной оболочкой:

// Wrapper.h
struct opaque_wrapper* make_instance(void);
void release_instance(struct opaque_wrapper*);
ClassName *ClassName_new(struct opaque_wrapper*);

// Wrapper.cpp
struct opaque_wrapper {
    std::shared_ptr<Lib::Instance> p_Instance;
};
opaque_wrapper* make_instance() {
    return new opaque_wrapper{std::make_shared<Lib::Instance>()};
}
void release_instance(struct opaque_wrapper* instance) {
    delete instance;
}
ClassName *ClassName_new(struct opaque_wrapper* instance) {
    return ClassName_new(instance->p_Instance);
}
0 голосов
/ 25 сентября 2019

Вы не можете использовать классы из C ++ в C.

Вы можете определить прототипы функций функций C для соглашения о вызовах C, которые будут использоваться из C ++, с помощью следующего кода оболочки в заголовочном файле:

#ifdef __cplusplus
extern "C" {
#endif

/* put here C calling convention C functions */

#ifdef __cplusplus
};
#endif

, и вы получите файл определений, который можно использовать как в C, так и в C ++.__cplusplus - это макрос, определенный компилятором c ++ при компиляции кода C ++, и он вводит среду extern "C" { для поддержки функций C.Эти функции следуют соглашениям о вызовах в стиле C (вы не можете их перегружать, вы не можете использовать определения методов или определять там классы)

...