2017-08-02 4 views
2

SwiftからC++ヘッダーで書かれたenumの値にアクセスしようとしています。具体的には、OpenCVのhppヘッダーファイルにenumという値を設定して、その値をSwiftに公開したいとします。私はスウィフトとObjective-Cの間のブリッジのヘッダーを設定し、私は公開したいC++のenum値の周りにラッパーを置くことを試みてきたが、コンパイラはそれについて満足していないです:SwiftからC++ Enumにアクセス

imgproc.hpp: C++ヘッダファイル

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

ブリッジヘッダ

#import "OpenCVWrapper.h" 

OpenCVWrapper.h:私のObjective-C WRA PPERクラスはスウィフト

#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 

にさらされる私はOpenCVWrapper.mmにこの列挙宣言とC++コード(OpenCVの)輸入を移動した場合、コンパイラはそれでOKですが、私もちゃんとそれを使用することができますが、私はしたいですこの列挙型をSwiftに公開してヘッダファイルに入れなければなりません。しかし、C++のenumをObjective-Cヘッダーに直接公開すると、何か問題があります。

Objective-CヘッダからC++の定数/列挙型に直接アクセスして、Swiftと橋渡しすることは可能ですか?

私はexternをthisthisのように見ましたが、C++定数はまだ私のセットアップで認識されません。

+1

https://stackoverflow.com/questions/35229149/interacting-with-c-classes-from-swiftで指摘されているように、ブリッジヘッダーファイル*はC++を処理できません。 .hppファイルを直接または間接的に別の.hファイルに含めるかどうかは関係ありません。 –

+0

CからSwiftに至るのは簡単でしょうか? OpenCV 2には、[OpenCV用のC API](http://docs.opencv.org/2.4/modules/core/doc/old_basic_structures.html)がありました。残念ながら、OpenCV 3のメンテナンスは廃止されたようだ:[openCVはまもなくC APIサポートを失うだろう](http://answers.opencv.org/question/17546/opencv-will-drop-c-api-support-soon/ )。これは2013年からのQ&Aです。「opencv c api」の検索で、C APIのドキュメントが見つかりました。 OpenCV 3の個々のクラスのページを参照してください。 – Scheff

+0

@Scheff、将来的には機能しなくなる可能性のある解決策を避けたいと思いますが、参照していただきありがとうございます。 – HuaTham

答えて

0

C++列挙型と同じ数値を持つ新しい独立した列挙型を.hファイルに作成し、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; 

明らかに、それらが何であれ、正しい数字を入れます。元のC++ヘッダーが変更された場合は、.mmファイルをチェックインします。

+0

これは私がこれを行う解決策を探している理由です:値をハードコーディングするのを避けるためです。 C++コードが後で値の定義を変更した場合、そのSwiftコードはこれによって中断されます。 – HuaTham

1

OpenCV C++ライブラリで定義されている値は、同じライブラリに定義されているAPIで使用され、これらのAPIはSwiftで使用するためにラップする必要があります。ラッパー層には、C++のenumとSwiftの間で変換するためのコードが含まれていて、C++ enumの値を変更することでSwiftコードが壊れないようにすることもできます。これは、SwiftとC++ enumの両方の値をラッパーが認識しているために可能です。

CPP.hそれを呼び出す、のは、C++のヘッダファイルを言ってみましょう、があります。

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

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

実装が我々の目的のために重要ではありません。スウィフトにさらさCPPWrapper.hでラッパーAPIは、

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 

上記のコードスニペットは、完全なソースコードファイルではなく、与えるべきですあなたは何が起こっているのか考えています。コードはさまざまな方法でより堅牢にすることができますが、それは短い答えの範囲を超えています。

+0

これは基本的に質問をして数日後に私がやっていることです。とにかくありがとう。私はあなたの答えをrep'dしましたが、将来的にはより合理化されたアプローチのために質問を開いたままにしています。 – HuaTham

関連する問題