簡體   English   中英

C ++-定義類模板(標題/源文件)

[英]C++ - Defining class template (header/source file)

我想在voreen中創建一個處理器(例如這個.cpp | .h ),以移植此OTB應用程序:

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

我已經將幾乎所有參數編碼為屬性,等等。

如果看一下376 ,您會看到FloatVectorImageType :: SizeType的類模板,這是一個typedef類型。

我對c ++模板不熟悉,所以我的第一個問題是我應該將該模板的實現放在處理器的.cpp或.h文件中的什么位置? 簡要介紹一下c ++教程和其他處理器示例(如上述示例),我發現我必須在標頭中聲明模板,並在.cpp中進行定義。

問題是編譯器不允許我在.cpp中定義typedef類型的模板類。 無法識別typedef。

那么,有人可以在這里指出我正確的方向嗎?

段處理器

#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

段處理器

#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”未命名類型(已修復)

我對c ++模板不熟悉,所以我的第一個問題是我應該將該模板的實現放在處理器的.cpp或.h文件中的什么位置?

將其放在頭文件中。 這是最簡單,最可靠的解決方案。 通常,您希望將功能的定義(即,功能主體)放入源文件(.cpp)中,因為源文件可以獨立編譯。 但這對於模板 (*) 是不可能的

(*)略有簡化。

類模板只是類的藍圖, 函數模板函數的藍圖。 也就是說, 函數模板不是函數 ,換句話說,“模板函數”具有誤導性,它不是函數,而是模板/藍圖。

從函數模板(或從類模板的類)構建函數的過程稱為實例化 其結果是一個實例化的功能,或者更一般地,函數模板特殊化

模板專業化不是模板 函數模板專門化只是一個具有奇怪名稱的普通函數; 類模板專業化只是一個名稱很奇怪的類。

僅針對某些特定的模板參數集實例化模板:

  • 如果您明確要求將其實例化
  • 或者,如果您只是使用特殊化(-> 隱式實例化)。

到目前為止,第二種方法更為普遍。 一個例子:

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

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

這將為模板參數int實例化類模板 my_type ,並為模板參數double實例化一次。 這將創建兩個具有相似名稱的獨立 my_type<int> 相關的類型: 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*

第二次調用將自動推導 template參數為int 再次,我們創建(隱式實例化)了兩個具有相似名稱的函數: foo<int>(int) (名稱為foo<int> ,並且具有單個類型為int函數參數)和foo<double>(double)


將模板的定義放在源文件中為什么不好:請參閱為什么只能在頭文件中實現模板?

簡短版本:由於模板是藍圖,為了使用它們,編譯器必須實例化它們。 但是它只能實例化它所知道的

如果你聲明函數模板foo在頭文件templ.h ,在定義它templ.cpp和使用它main.cpp ,則:

  • main.cpp ,編譯器不知道函數模板的定義。 它只能實例化foo聲明 ,而不能實例化定義。

  • templ.cpp ,編譯器確實知道該定義,並且可以實例化它。 但是,它不知道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";
}

現在,您告訴編譯器在哪里尋找名稱Bar ,即在Foo

這是我為幫助您而編寫的模板的簡短示例:
在標題中:

typedef TemplatedClassName< ParameterValue0, ParameterValue1 > TemplateAlias;

在源文件中:
//顯式模板實例化

template class TemplatedClassName< ParameterValue0, ParameterValue1 >;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM