Цель c — получить доступ к C ++ Enum из Swift

Я пытаюсь получить доступ enumЗначения написаны в заголовке C ++ из Swift. В частности, у меня есть это enum в заголовочном файле hpp OpenCV, который я хотел бы представить его значения в Swift. Я попытался установить соединительный заголовок между Swift и Objective-C и поместить оболочку вокруг значений перечисления C ++, которые я хотел бы раскрыть, но компилятору это не нравится:

imgproc.hpp: Заголовочный файл C ++

enum ThresholdTypes {
THRESH_BINARY     = 0,
THRESH_BINARY_INV = 1,
THRESH_TRUNC      = 2,
...
};

соединительный заголовок:

#import "OpenCVWrapper.h"

OpenCVWrapper.h: Мой класс Обёртки Objective-C будет выставлен Swift

#ifdef __cplusplus
#import <opencv2/core.hpp>
#import <opencv2/imgproc.hpp>
#endif

#import <Foundation/Foundation.h>

@interface OpenCVWrapper : NSObject

typedef enum {
Binary = cv::THRESH_BINARY,  // ERROR: use of undeclared identifier `cv`
BinaryInv = cv::THRESH_BINARY_INV  // ERROR: use of undeclared identifier `cv`
} ThresholdingType;

...

@end

Если я переместить это объявление enum и импорт кода C ++ (OpenCV) в OpenCVWrapper.mm тогда с компилятором все в порядке, и я также могу использовать его просто отлично, но я хочу показать это перечисление Swift, так что оно должно быть в заголовочном файле. Однако что-то не так, когда я выставляю перечисление C ++ прямо в заголовке Objective-C.

Можно ли получить доступ к константам / перечислениям C ++ непосредственно из заголовка Objective-C таким образом, чтобы он мог быть мостом к Swift?

Я смотрел на использование Extern, как этот а также этот но константы C ++ все еще не распознаются в моей настройке.

2

Решение

enum Значения, определенные в библиотеке OpenCV C ++, предназначены для использования с API, определенными в той же библиотеке, и эти API должны быть упакованы для использования в Swift. Слой оболочки также может включать в себя код для перевода между enums в C ++ и Swift таким образом, что меняются значения C ++ enums не будет нарушать код Swift. Это возможно, потому что оболочка знает как о Swift, так и о C ++ enum ценности.

Допустим, заголовочный файл C ++, назовите его CPP.hимеет:

namespace cv {
enum ThresholdTypes {
THRESH_BINARY     = 0,
THRESH_BINARY_INV = 111,
THRESH_TRUNC      = 222
};

void useThreshold(ThresholdTypes t);
ThresholdTypes returnThreshold();
};

Реализация не важна для наших целей. API-оболочка, в CPPWrapper.h, подверженный воздействию Swift, может выглядеть

typedef enum {
THRESH_BINARY,
THRESH_BINARY_INV,
THRESH_TRUNC,
THRESH_UNKNOWN
} ThresholdTypesWrapper;

@interface CPPWrapper : NSObject

// The wrapper API operates in terms of wrapper `enum` values only.
// Translation between these and C++ `enum`s happens in the wrapper
// implementation.
+(void)useThreshold: (ThresholdTypesWrapper)thresholdType;
+(ThresholdTypesWrapper)returnThreshold;

@end

А вот реализация оболочки, CPPWrapper.mm:

cv::ThresholdTypes thresholdWrapped2Native(ThresholdTypesWrapper t) {
if (t==THRESH_BINARY) return cv::THRESH_BINARY;
else if (t==THRESH_BINARY_INV) return cv::THRESH_BINARY_INV;
else if (t==THRESH_TRUNC) return cv::THRESH_TRUNC;
// This should be very unlikely.
else throw std::runtime_error("Unknown threshold value detected.");
}

ThresholdTypesWrapper thresholdNative2Wrapped(cv::ThresholdTypes t) {
if (t==cv::THRESH_BINARY) return THRESH_BINARY;
else if (t==cv::THRESH_BINARY_INV) return THRESH_BINARY_INV;
else if (t==cv::THRESH_TRUNC) return THRESH_TRUNC;
// We could throw instead, but returning unknown is more forgiving if
// a new C++ enum value is added.
else return THRESH_UNKNOWN;
}

@implementation CPPWrapper

+(void)useThreshold: (ThresholdTypesWrapper)thresholdType {
cv::useThreshold(thresholdWrapped2Native(thresholdType));
}

+(ThresholdTypesWrapper)returnThreshold {
return thresholdNative2Wrapped(cv::returnThreshold());
}

@end

Приведенные выше фрагменты кода не являются полными файлами исходного кода, но должны дать вам представление о том, что происходит. Код можно сделать более надежным несколькими способами, но это выходит за рамки краткого ответа.

1

Другие решения

Единственное, что вы можете сделать, это создать новый независимый перечисление в вашем файле .h, который имеет те же числовые значения, что и перечисление C ++, а затем в вашем файле Objective C ++ используйте утверждения времени компиляции (static_assert), чтобы проверить, что значения одинаковы.

typedef enum {
Binary = 7,  // cv::THRESH_BINARY: use of undeclared identifier `cv`
BinaryInv = 12  // cv::THRESH_BINARY_INV: use of undeclared identifier `cv`
} ThresholdingType;

Очевидно, ставя правильные числа, какими бы они ни были. И проверка в файле .mm, в случае изменения исходного заголовка C ++.

0

По вопросам рекламы [email protected]