Cython Create C псевдоним функции - PullRequest
1 голос
/ 21 июня 2019

У меня есть два варианта функции: void func1(double *) и void func2(double *), которые извлечены из кода C ++.

Я хочу иметь возможность написать функцию или отображение, которое обернет их:

cdef func_alias(int choice):
   if choice == 0:
       return func1
   elif choice == 1:
       return func2

Но компилируется Cannot convert 'void (double *) nogil' to Python object

В качестве альтернативы я попытался использовать dicts, который выдает ту же ошибку:

cdef dict func_dict = {0: func1, 1: func2}

Но я получаю ту же ошибку.

Я не уверен, смогу ли я что-то сделать в соответствии с

from libcpp.map import map
cdef map[int, void] func_map = {0: func1, 1: func2}

, что приводит к Cannot interpret dict as type 'map[int,void]'

1 Ответ

2 голосов
/ 21 июня 2019

Ваша функция func_alias не определяет тип возвращаемого значения (что означает, что по умолчанию будет использоваться объект python).Поскольку указатели на функции не являются допустимыми объектами Python, Cython выдает это сообщение об ошибке при компиляции.Мы можем определить ctypedef, представляющий указатель на функцию, и использовать его в качестве возвращаемого типа.Вот пример, который делает именно это:

ctypedef void (* double_func)(double *)

cdef void func_1(double *arg1):
    print(1, arg1[0])

cdef void func_2(double *arg1):
    print(2, arg1[0])

cdef double_func func_alias(int choice):
    if choice == 1:
        return func_1
    elif choice == 2:
        return func_2

cdef double test_input = 3.14
func_alias(1)(&test_input)
func_alias(2)(&test_input)

В качестве примечания: если у вас есть только фиксированное количество потенциальных указателей на функции для рассмотрения, я бы рассмотрел использование enum вместо операторов if.Я могу привести пример этого, если это поможет.Дайте мне знать, если что-то неясно.

Обновление: Глядя на вторую часть вопроса, я вижу, что вы также рассматривали возможность использования хэш-карты для сопоставления целых чисел с указателями функций.Хотя вы не можете использовать dict для этого, поскольку они могут хранить только объекты Python, вы можете использовать map (или unordered_map, который должен работать немного лучше).К сожалению, вы не можете использовать удобный синтаксис python dict для инициализации всех значений dict, и вместо этого вы должны добавлять элементы по одному.Вот этот подход в действии:

from libcpp.unordered_map cimport unordered_map

ctypedef void (* double_func)(double *)
cdef unordered_map[int, double_func] func_map
func_map[1] = func_1
func_map[2] = func_2

cdef void func_1(double *arg1):
    print(1, arg1[0])

cdef void func_2(double *arg1):
    print(2, arg1[0])

cdef double_func func_alias(int choice):
    return func_map[choice]

cdef double test_input = 3.14
func_alias(1)(&test_input)
func_alias(2)(&test_input)
...