1

この OTB アプリケーションを移植するvoreen (この.cpp | .hのような) でプロセッサを作成したい:

http://hg.orfeo-toolbox.org/OTB/file/ca4366bb972e/Applications/Segmentation/otbSegmentation.cxx

ほとんどすべてのパラメーターをプロパティなどにコーディングしましたが..

376のように見ると、typedef 型である FloatVectorImageType::SizeType のクラス テンプレートが表示されます。

私は C++ テンプレートに慣れていないので、最初の質問は、このテンプレートの実装をプロセッサの .cpp または .h ファイルのどこに置くべきかということでした。上記のような c++ チュートリアルやその他のプロセッサの例を簡単に見てみると、ヘッダーでテンプレートを宣言し、.cpp で定義する必要があることがわかりました。

問題は、コンパイラが .cpp 内で typedef 型のテンプレート クラスを定義できないことです。typedef が認識されません。

それで、誰かが私をここで正しい方向に向けることができますか?

セグメンテーションプロセッサ.h

#ifndef OTBSEGMENTATIONAPPLICATION_H
#define OTBSEGMENTATIONAPPLICATION_H

#include "otbVectorImage.h"
#include "modules/otb/ports/otbimageport.h"
#include "modules/otb/ports/otbvectorimageport.h"
#include "voreen/core/properties/boolproperty.h"

//..more includes here

namespace voreen {

class OTBSegmentationApplication : public OTBImageFilterProcessor
{
public:
    OTBSegmentationApplication();

    virtual ~OTBSegmentationApplication();

    virtual Processor* create() const;

    virtual std::string getCategory() const { return "Applications"; }
    virtual std::string getClassName() const { return "Segmentation Application"; }
    virtual CodeState getCodeState() const { return CODE_STATE_EXPERIMENTAL;}//STABLE, TESTING, EXPERIMENTAL

    virtual std::string getProcessorInfo() const;

    /** Images typedefs */
    typedef otb::VectorImage<double, 2> VectorImageType;
    typedef ImageType               LabelImageType;
    typedef ImageType               MaskImageType;

    typedef VectorImageType::SizeType size;

    // Segmentation filters typedefs
    // Edison mean-shift
    typedef otb::MeanShiftVectorImageFilter<VectorImageType,VectorImageType,LabelImageType> EdisonSegmentationFilterType;
    EdisonSegmentationFilterType::Pointer edisonFilter;

    // Home made mean-shift
    typedef otb::MeanShiftSegmentationFilter<VectorImageType, LabelImageType, VectorImageType> MeanShiftSegmentationFilterType;
    MeanShiftSegmentationFilterType::Pointer meanshiftFilter;

    // Simple connected components
    typedef otb::Functor::ConnectedComponentMuParserFunctor<VectorImageType::PixelType> FunctorType;

    typedef itk::ConnectedComponentFunctorImageFilter <VectorImageType, LabelImageType, FunctorType, MaskImageType> ConnectedComponentSegmentationFilterType;
    ConnectedComponentSegmentationFilterType::Pointer ccFilter;

    typedef itk::ScalarConnectedComponentImageFilter<LabelImageType, LabelImageType> LabeledConnectedComponentSegmentationFilterType;
    LabeledConnectedComponentSegmentationFilterType::Pointer labeledCCFilter;

    //..more typedefs here

protected:
    virtual void setDescriptions() {
        setDescription("Performs segmentation of an image, and output either a raster or a vector file. In vector mode, large input datasets are supported.");
    }
    void process();
    virtual void initialize() throw (tgt::Exception);
    virtual void deinitialize() throw (tgt::Exception);

    /** TEMPLATE DECLARATION (?) */

    template<class TInputImage, class TSegmentationFilter>
    VectorImageType::SizeType GenericApplySegmentation(otb::StreamingImageToOGRLayerSegmentationFilter
                                                       <TInputImage, TSegmentationFilter> * streamingVectorizedFilter, TInputImage * inputImage,
                                                       const otb::ogr::Layer& layer, const unsigned int outputNb);
    virtual void updateFilterSelection();
    virtual void updateModeSelection();

private:

    OTBVectorImagePort inPort_;
    StringOptionProperty filter_; ///< Select segmentation algorithm
    OTBVectorImagePort vectorOutPort_;
    OTBImagePort vectorMaskInPort_;
    OTBImagePort outPort_;

    //..more property definitions here

    static const std::string loggerCat_; ///< Category used in logging
};

} // namespace

#endif // OTBSEGMENTATIONAPPLICATION_H

セグメンテーションプロセッサ.cpp

#include "segmentationprocessor.h"
#include "voreen/core/voreenapplication.h"

namespace voreen {

const std::string OTBSegmentationApplication::loggerCat_("voreen.OTBSegmentationApplication");

OTBSegmentationApplication::OTBSegmentationApplication()
    :OTBImageFilterProcessor(),
      inPort_(Port::INPORT, "IN Multiband Image", 0),
      vectorOutPort_(Port::OUTPORT, "OUT Multiband Image", 0),
      vectorMaskInPort_(Port::INPORT, "IN Mask Image", 0),
      outPort_(Port::OUTPORT, "OUT OTB Image", 0),

      filter_("selectFilter", "Segmentation algorithm"),

      //.. more properties code here

{
    addPort(inPort_);
    addPort(vectorOutPort_);
    addPort(vectorMaskInPort_);
    addPort(outPort_);

    addProperty(filter_);

    //.. adding the rest of properties here

    edisonFilter = EdisonSegmentationFilterType::New();
    meanshiftFilter = MeanShiftSegmentationFilterType::New();
    ccFilter = ConnectedComponentSegmentationFilterType::New();

    //..instantiating more filters needed in implementation here

}

Processor* OTBSegmentationApplication::create() const {
    return new OTBSegmentationApplication();
}

OTBSegmentationApplication::~OTBSegmentationApplication() {

}

void OTBSegmentationApplication::initialize() throw (tgt::Exception) {
    Processor::initialize();
}

void OTBSegmentationApplication::deinitialize() throw (tgt::Exception) {
    Processor::deinitialize();
}

std::string OTBSegmentationApplication::getProcessorInfo() const {
    return "Segmentation Application";
}

void OTBSegmentationApplication::updateFilterSelection() {
    //code for visual updates on properties here
}

void OTBSegmentationApplication::updateModeSelection() {
    //code for visual updates on properties here
}

    //TEMPLATE IMPLEMENTATION HERE (?)
template<class TInputImage, class TSegmentationFilter>
OTBSegmentationApplication::VectorImageType::SizeType OTBSegmentationApplication::GenericApplySegmentation(otb::StreamingImageToOGRLayerSegmentationFilter<TInputImage,
                             TSegmentationFilter> * streamingVectorizedFilter, TInputImage * inputImage, const otb::ogr::Layer& layer, const unsigned int outputNb)
    {
        typedef  TSegmentationFilter SegmentationFilterType;
        typedef  typename SegmentationFilterType::Pointer SegmentationFilterPointerType;
        typedef otb::StreamingImageToOGRLayerSegmentationFilter<TInputImage,SegmentationFilterType> StreamingVectorizedSegmentationOGRType;

    //..the rest of template code here
}


void OTBSegmentationApplication::process() {

    try
    {
        //PROCESSOR IMPLEMENTATION GOES HERE
        LINFO("Segmentation Application Connected");
    }
    catch (int e)
    {
        LERROR("Error in Segmentation Applicationn");
        return;
    }
}

}   // namespace

エラー: 'VectorImageType' はタイプを指定していません (修正済み)

4

2 に答える 2

7

私は C++ テンプレートに慣れていないので、最初の質問は、このテンプレートの実装をプロセッサの .cpp または .h ファイルのどこに置くべきかということでした。

ヘッダーファイルに入れます。これが最もシンプルで堅牢なソリューションです。通常、ソース ファイルは独立してコンパイルできるため、関数の定義 (関数本体など) をソース ファイル (.cpp) に配置します。しかし、これはテンプレート(*)では不可能です

(*) 少し簡略化しています。

クラス テンプレートは単なるクラスの設計図であり、関数テンプレートは関数の設計図です。つまり、関数テンプレートは関数ではありません。つまり、「テンプレート関数」は誤解を招きやすく、関数ではなくテンプレート/ブループリントです。

関数テンプレートから関数 (またはクラス テンプレートからクラス) を構築するプロセスは、インスタンス化と呼ばれます。結果は、インスタンス化された関数、またはより一般的には関数テンプレートの特殊化です。

テンプレートの特殊化はテンプレートではありません。関数テンプレートの特殊化は、変な名前の普通の関数です。クラス テンプレートの特殊化は、変な名前の単なるクラスです。

テンプレートは、テンプレート引数の特定のセットに対してのみインスタンス化されます。

  • インスタンス化を明示的に要求した場合
  • または、特殊化を使用するだけの場合 (->暗黙的なインスタンス化)。

2 番目の方法は、はるかに一般的です。例:

template<class T>
struct my_type
{
    T mem;
};

// using the specialization -> implicit instantiation
my_type<int> o;
my_type<double> p;

これにより、クラス テンプレート my_typeがテンプレート引数に対して 1 回インスタンス化され、テンプレート引数に対して 1 回インスタンス化さintれますdouble。これにより、類似した名前を持つ 2 つの独立した関連のない型が作成ます。my_type<int>my_type<double>

関数についても同様です。ただし、関数の場合は通常、テンプレート引数を明示的に指定しません。代わりに、関数の引数の型からコンパイラにテンプレートの引数を推測させます。例:

template<class T>
void foo(T param)
{
    std::cout << param;
}

foo<int>(42);  // explicitly specifying the template arguments -- DON'T DO THAT
foo(21);       // template argument *deduction*

2 番目の呼び出しでは、テンプレート引数が であると自動的に推定intされます。繰り返しますが、同様の名前を持つ 2 つの関数を (暗黙的にインスタンス化して) 作成しましfoo<int>(int)た: (名前はfoo<int>で、 type の単一の関数パラメーターを持ちますint)foo<double>(double)


テンプレートの定義をソース ファイルに入れるのがよくない理由:なぜテンプレートをヘッダー ファイルにしか実装できないのですか?を参照してください。

短いバージョン: テンプレートは設計図であるため、それらを使用するには、コンパイラがそれらをインスタンス化する必要があります。しかし、知っていることをインスタンス化することしかできません。

fooヘッダー ファイルで関数テンプレートを宣言する場合templ.h、 で定義して でtempl.cpp使用すると、次のようになりますmain.cpp

  • ではmain.cpp、コンパイラは関数テンプレートの定義を認識していません。の宣言のみをインスタンス化できますfooが、定義はインスタンス化できません。

  • ではtempl.cpp、コンパイラは定義を認識しており、インスタンス化できます。ただし、外部での使用については認識していません。templ.cppしたがって、外部で使用される引数のすべてのセットに対してインスタンス化することはできません。

OPの例では、それは機能しますが、見落としのようです:

[templ.h]

template<class T>
void foo(T);

void ordinary_function();

[templ.cpp]

#include "templ.h"

template<class T>
void foo(T p)
{
    std::cout << p;
}

void ordinary_function()
{
    foo(42);     // implicit instantiation of foo<int>
    foo(2.5);    // implicit instantiation of foo<double>
}

[main.cpp]

#include "templ.h"
int main()
{
    foo(23);    // works fine, uses the foo<int> defined in templ.cpp
    foo('a');   // linker error: foo<char> not defined
    return 0;
}

定義は でfoo<char>インスタンス化されておらずtempl.cpp、 でインスタンス化できないためmain.cpp、リンカー エラーが発生します。

そのため、この動作に依存するべきではありません。何らかの理由で関数テンプレートをヘッダー ファイルで定義したくない場合は、明示的なインスタンス化を使用できます。少なくとも、明示的なインスタンス化は明示的であり、文書化する必要があるため、予期せぬ事態が発生することはありません。


コンパイラが実際に不満を言っている問題は、テンプレートとは何の関係もありません;) これは単なる名前検索の問題です。簡単な例:

#include <iostream>

struct Foo
{
    typedef int Bar;

    void do_something();
};

Bar Foo::do_something()
{
    std::cout << "something\n";
}

コンパイラが行Bar Foo::do_something()を見るとBar、その名前が何を指しているのかを見つけることができません。したがって、エラー。一方で:

#include <iostream>

struct Foo
{
    typedef int Bar;

    void do_something();
};

Foo::Bar Foo::do_something()
{
    std::cout << "something\n";
}

これで、 name を探す場所Bar、つまり 内をコンパイラに指示しましたFoo

于 2013-11-12T12:24:49.753 に答える
0

あなたを助けるために私が書いたテンプレートの短い例を次に示します
:

typedef TemplatedClassName< ParameterValue0, ParameterValue1 > TemplateAlias;

ソース ファイル内:
// 明示的なテンプレートのインスタンス化

template class TemplatedClassName< ParameterValue0, ParameterValue1 >;
于 2013-11-12T12:10:59.867 に答える