Я пытаюсь получить доступ 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 ++ все еще не распознаются в моей настройке.
enum
Значения, определенные в библиотеке OpenCV C ++, предназначены для использования с API, определенными в той же библиотеке, и эти API должны быть упакованы для использования в Swift. Слой оболочки также может включать в себя код для перевода между enum
s в C ++ и Swift таким образом, что меняются значения C ++ enum
s не будет нарушать код 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
Приведенные выше фрагменты кода не являются полными файлами исходного кода, но должны дать вам представление о том, что происходит. Код можно сделать более надежным несколькими способами, но это выходит за рамки краткого ответа.
Единственное, что вы можете сделать, это создать новый независимый перечисление в вашем файле .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 ++.