Определение шаблона класса (заголовок / исходный файл)

Я хочу создать процессор во ворин (как этот .CPP | .час) портируем это OTB-приложение:

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

Я закодировал почти все параметры в свойствах и т. Д., Но …

Если вы посмотрите на как 376, вы увидите шаблон класса FloatVectorImageType :: SizeType, тип определения типа.

Я не знаком с шаблонами c ++, поэтому мой первый вопрос был, где я должен поместить реализацию этого шаблона, в файл .cpp или .h процессора? Кратко рассмотрим учебники по c ++ и другие примеры процессоров, такие как один выше, Я понял, что должен объявить шаблон в заголовке и определить его в .cpp.

Проблема в том, что компилятор не позволяет мне определять шаблонный класс типа typedef внутри .cpp. Тип определения не распознан ..

Итак, кто-то может указать мне правильное направление здесь?

segmentationprocessor.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

segmentationprocessor.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» не называет тип (исправлено)

1

Решение

Я не знаком с шаблонами 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;

Это будет создавать шаблон класса my_type один раз для аргумента шаблона intи один раз для аргумента шаблона double, Это создает два независимый а также несвязанный типы с похожими именами: 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*

Второй звонок будет автоматически выводить аргумент шаблона должен быть int, Опять же, мы создали (неявно созданы) две функции с похожими именами: foo<int>(int) (имя foo<int> и он имеет единственный параметр функции типа 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";
}

Теперь вы сказали компилятору, где искать имя Barа именно внутри Foo,

7

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

Вот краткий пример шаблонов, которые я написал, чтобы помочь вам:
в заголовке:

typedef TemplatedClassName< ParameterValue0, ParameterValue1 > TemplateAlias;

в исходном файле:
// явная реализация шаблона

template class TemplatedClassName< ParameterValue0, ParameterValue1 >;
0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector