Могу ли я экспортировать шаблонный класс c ++ в C и, следовательно, в Python с ctypes?

0

Для класса без шаблона я бы написал что-то вроде этого

Но я не знаю, что мне делать, если мой класс является классом шаблона.

Я пробовал что-то вроде этого, и он не работает.

extern "C" {
    Demodulator<double>* Foo_new_double(){ return new Demodulator<double>(); }
    Demodulator<float>* Foo_new_float(){ return new Demodulator<float>(); }
    void demodulateDoubleMatrix(Demodulator<double>* demodulator, double * input, int rows, int columns){ demodulator->demodulateMatrixPy(input, rows, columns) }
}
  • 0
    Вы не можете иметь C ++ в extern "C"
  • 0
    В ссылке, которую я дал, они используют оператор new в extern C. Это C ++, верно? Так что или они не правы или вы, верно?
Показать ещё 10 комментариев
Теги:

2 ответа

1

Примечание. Ваш вопрос частично противоречит коду, поэтому я сейчас игнорирую код.

Шаблоны C++ - это разработанный макрокоманд, который разрешается во время компиляции. Другими словами, двоичный код содержит только код из экземпляров шаблонов (это то, что вы получаете, когда вы применяете параметры, типично типы, к шаблону), и это все, что вы можете экспортировать из двоичного кода на другие языки. Экспорт их похож на экспорт любого обычного типа, например, std::string.

Поскольку сами шаблоны не выдерживают компиляцию, вы не можете экспортировать их из двоичного, а не из C, а не в Python, даже в C++! Для последнего вы можете предоставить сами шаблоны, но это не включает их в двоичный файл.

Два предположения:

  • Экспорт/импорт работ через двоичные файлы. Конечно, вы можете написать импорт, который анализирует C++.
  • C++ указывает (или указанный?) Экспорт шаблонов, но, насколько я знаю, это не реализовано в дикой природе, поэтому я оставил эту опцию.
0

Язык C++ запущен как надмножество C: То есть он содержит новые ключевые слова, синтаксис и возможности, которые C не предоставляет. C не имеет понятия class, не имеет понятия функции-члена и не поддерживает понятие ограничений доступа. C также не поддерживает наследование. Однако действительно большая разница - это шаблоны. C имеет макросы и что это.

Поэтому нет, вы не можете напрямую разоблачить код C++ на C любым способом, вам придется использовать код C-стиля в вашем C++, чтобы открыть слой C++.

 template<T> T foo(T i) { /* ... */ }
 extern "C" int fooInt(int i) { return foo(i); }

Однако C++ изначально был генератором кода C, а C++ все еще может взаимодействовать (с одной стороны) с C ABI: функции-члены фактически реализуются путем поворота функции this->function(int arg); в ThisClass0int1(this, arg); или что-то типа того. В теории вы могли бы написать что-то, чтобы сделать это с вашим кодом, возможно, используя clang.

Но это нетривиальная задача, которая уже хорошо справляется с SWIG, Boost :: Python и Cython.

Однако проблема с шаблонами заключается в том, что компилятор игнорирует их до тех пор, пока вы не будете "создавать" (использовать) их. std :: vector <> не является конкретной вещью, пока вы не укажете std::vector<int> или что-то еще. И теперь единственной конкретной реализацией этого является std::vector<int>. Пока вы не указали его где-нибудь, std::vector<string> не существует в вашем двоичном файле.

Вероятно, вы хотите начать с того, что посмотрите на что-то вроде этого http://kos.gd/2013/01/5-ways-to-use-python-with-native-code/, выберите инструмент, например SWIG, а затем запустите создавая интерфейс, чтобы выявить то, что вам нужно/нужно C. Это намного меньше, чем создание самих оберток. В зависимости от того, какой инструмент вы используете, это может быть так же просто, как написание строки using std::vector<int> или typedef std::vector<int> IntVector или что-то в этом роде.

---- РЕДАКТИРОВАТЬ ----

Проблема с классом шаблона заключается в том, что вы создаете цельный тип, который C не может понять, рассмотрите:

template<typename T>
class Foo {
    T a;
    int b;
    T c;
public:
    Foo(T a_) : a(a_) {}
    void DoThing();
    T GetA() { return a; }
    int GetB() { return b; }
    T GetC() { return c; }
};

Язык C не поддерживает ключевое слово class, не важно понимать, что члены a, b и c являются частными или конструкторами, а C не понимает функции-члены.

Опять же, он не понимает шаблоны, поэтому вам нужно будет сделать то, что C++ делает автоматически, и создать экземпляр вручную:

struct FooDouble {
    double a;
    int b;
    double c;
};

Кроме того, все эти переменные являются частными. Так вы действительно хотите разоблачить их? Если нет, вам, вероятно, просто нужно ввести typedef "FooDouble" к тому же размеру, что и Foo, и сделать макрос для этого.

Затем вам нужно написать замены для функций-членов. C не понимает конструкторы, поэтому вам нужно будет написать

extern "C" FooDouble* FooDouble_construct(double a);

FooDouble* FooDouble_construct(double a) {
    Foo* foo = new Foo(a);
    return reinterept_cast<FooDouble*>(foo);
}

и деструктор

extern "C" void FooDouble_destruct(FooDouble* foo);

void FooDouble_destruct(FooDouble* foo) {
    delete reinterpret_cast<Foo*>(foo);
}

и аналогичный проход для аксессуаров.

  • 0
    Что ж, мне нужно экспортировать только один класс, поэтому я думаю, что стоимость копания в SWIG более чем выгодна. Я также понимаю, что в двоичном коде будут только те функции, которые вызываются откуда-то в коде. Таким образом, для каждого используемого типа будет одна функция fooInt, fooDouble или что-то в этом роде. Чего я не понимаю, так это того, могу ли я предоставить шаблонный класс c ++ для C с каким-то точным типом. Как extern "C" Foo * FooInt_new (новый Foo <int> ()). И почему это не работает? Я дал это право типа? Почему он не может скомпилировать этот класс с этим типом?
  • 0
    Потому что C не поддерживает шаблоны. Когда вы говорите extern "C" ... вы даете обещание компилятору, что все в elipsis будет кодом C и, опять же, C не имеет шаблонов.
Показать ещё 7 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню