gpt4 book ai didi

c++ - 模板类的工厂模式和模板类的新类型默认参数

转载 作者:太空宇宙 更新时间:2023-11-04 12:07:21 28 4
gpt4 key购买 nike

我有三层类,例如BaseSpreading(基类),IterativeMapSpreading(BaseSpreading的子类之一)和TentSpreading,BernoulliSpreading(IterativeMapSpreading的两个子类)。在所有类中都会出现一个称为generateSpreading的方法。用户定义的选项指定展开,例如“帐篷”或“bernoulli”。然后,if-else控制结构将调用相应子类的generateSpreading方法(“帐篷”和“bernoulli”将分别调用TentSpreading和BernoulliSpreading子类的generateSpreading方法)。

我知道如何通过将generateSpreading声明为虚拟的并定义一个基类指针(指向BaseSpreading)来解决我的问题。然后,可以根据用户选项在if-else控制结构内实例化派生的类对象。尽管这样的实例在控制结构的范围之外不可用,但是可以使用工厂模式将基类指针指向派生的类对象,例如this post。尽管基于虚拟方法的解决方案可以工作,但由于其性能较差,因此对我的目的没有用。我的模拟调用虚拟函数数百万次。

作为一种替代方法,我使用了模板编程。在这种情况下,我必须处理以下问题:嵌套模板类的实例在if-else结构的范围之外不可用。我的问题是在使用模板类时是否可以扩展工厂模式的想法。为了使这项工作可行,我将不得不创建一个指向模板基类的指针,然后将其指向实例化的模板子类,该子类在if-else结构内部定义。然后问题归结为为模板基类定义默认模板参数,这是我的难题。 This link给出了如何定义默认模板参数的示例,该默认模板参数不是“int”之类的众所周知的类型(链接示例的默认参数是 vector 的标准“分配器”模板)。

这些是我的脚本:

base_spreading.h:

#ifndef BASE_SPREADING_H_
#define BASE_SPREADING_H_

#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/numeric/ublas/vector.hpp>

template <class S>
class BaseSpreading
{
public:
BaseSpreading(S& spreading);

void generateSpreading(boost::numeric::ublas::vector<double>&);
private:
S& spreading_;
};

template <class S>
BaseSpreading<S>::BaseSpreading(S& spreading) : spreading_(spreading) {}

template <class S>
void BaseSpreading<S>::generateSpreading(
boost::numeric::ublas::vector<double>& spr) {
spreading_.generateSpreading(spr);
}

#endif /* BASE_SPREADING_H_ */

spreading_iterative_map.h

#ifndef SPREADING_ITERATIVE_MAP_H_
#define SPREADING_ITERATIVE_MAP_H_

#include <boost/numeric/ublas/vector.hpp>

template <class S>
class IterativeMapSpreading
{
public:
IterativeMapSpreading(S& spreading);

double evaluateMap(double);
void generateSpreading(boost::numeric::ublas::vector<double>&);
double sampleInitialPoint();
private:
S& spreading_;

void calculateFollowingPoints(boost::numeric::ublas::vector<double>&);
};

template <class S>
IterativeMapSpreading<S>::IterativeMapSpreading(S& spreading) :
spreading_(spreading) {}

template <class S>
void IterativeMapSpreading<S>::calculateFollowingPoints(
boost::numeric::ublas::vector<double>& spr) {
for (unsigned int i=1; i<spr.size(); ++i) {
spr(i) = spreading_.evaluateMap(spr(i-1));
}
}

template <class S>
double IterativeMapSpreading<S>::evaluateMap(double x) {
return spreading_.evaluateMap(x);
}

template <class S>
void IterativeMapSpreading<S>::generateSpreading(
boost::numeric::ublas::vector<double>& spr) {
spr(0) = spreading_.sampleInitialPoint();
calculateFollowingPoints(spr);
}

template <class S>
double IterativeMapSpreading<S>::sampleInitialPoint() {
return spreading_.sampleInitialPoint();
}

#endif /* SPREADING_ITERATIVE_MAP_H_ */

spreading_tent.h:

#ifndef SPREADING_TENT_H_
#define SPREADING_TENT_H_

#include <math.h>

#include "random_number_generation.h"

class TentSpreading
{
public:
TentSpreading(double uniformMin=0, double uniformMax=1,
double nonCentrality=0.5);

double evaluateMap(double);
double sampleInitialPoint();
private:
const double uniformMin_, uniformMax_, nonCentrality_;
double leftIntercept_, leftSlope_, rightIntercept_, rightSlope_;
boost::random::uniform_real_distribution<> Uniform;

void setLines();
void validateParameters() const;
};

#endif /* SPREADING_TENT_H_ */

spreading_tent.cpp:

#include "spreading_tent.h"

TentSpreading::TentSpreading(double uniformMin, double uniformMax,
double nonCentrality) : uniformMin_(uniformMin), uniformMax_(uniformMax),
nonCentrality_(nonCentrality), Uniform(uniformMin, uniformMax) {
setLines();
}

double TentSpreading::evaluateMap(double x) {
double y;

if((uniformMin_<=x) && (x<nonCentrality_))
y = leftSlope_*x+leftIntercept_;
else if((nonCentrality_<=x) && (x<=uniformMax_))
y = rightSlope_*x+rightIntercept_;

return y;
}

double TentSpreading::sampleInitialPoint() {
return Uniform(rng);
}

void TentSpreading::setLines() {
leftSlope_ = (uniformMax_-uniformMin_)/(nonCentrality_-uniformMin_);
leftIntercept_ = -uniformMin_*(uniformMax_-nonCentrality_)/
(nonCentrality_-uniformMin_);
rightSlope_ = -(uniformMax_-uniformMin_)/(uniformMax_-nonCentrality_);
rightIntercept_ = (pow(uniformMax_, 2)-uniformMin_*nonCentrality_)/
(uniformMax_-nonCentrality_);
}

最后,感兴趣的main.cpp部分:

  try  {
if (sbcOptions.mode=="sim-spr") {
boost::numeric::ublas::vector<double> sprVector(3);

if (sbcOptions.spr=="tent") {
TentSpreading tent(-1, 1, 0);
IterativeMapSpreading<TentSpreading> map(tent);
BaseSpreading<IterativeMapSpreading<TentSpreading> > spreading(map);
}

spreading.generateSpreading(sprVector);
}
}
catch(std::logic_error& logicError) {
logTee << logicError.what() << "\n";
return 1;
}

为了使用工厂模式,我尝试添加一个称为FactoryBaseSpreading的抽象基类,其中BaseSpreading是其子类。这是FactoryBaseSpreading的定义:

FactoryBaseSpreading {
public:
static BaseSpreading* create(std::string type);
}

FactoryBaseSpreading* FactoryBaseSpreading::create(std::string type) {
if (type == "tent") {
TentSpreading tent(-1, 1, 0);
IterativeMapSpreading<TentSpreading> map(tent);
return new BaseSpreading<IterativeMapSpreading<TentSpreading> >(map);
}
return NULL;
}

//Also, change the following line in base_spreading.h:
class BaseSpreading : public FactoryBaseSpreading

这样,我便可以在“main.cpp”中定义一个指向FactoryBaseSpreading的指针,并将其指向if-else结构内的相应子类,例如:

FactoryBaseSpreading* spreading;

try {
if (sbcOptions.mode=="sim-spr") {
boost::numeric::ublas::vector<double> sprVector(3);

if (sbcOptions.spr=="tent") {
spreading = FactoryBaseSpreading::create("tent");
}

spreading.generateSpreading(sprVector);
}
}
catch(std::logic_error& logicError) {
logTee << logicError.what() << "\n";
return 1;
}

前提是我在FactoryBaseSpreading中定义了一个虚拟generateSpreading方法,这可以编译并正常运行。但是,我试图避免的是使用虚函数,因此工厂模式无法解决我的问题。

因此,我想到了在BaseSpreading基类中定义“创建”方法,而不创建FactoryBaseSpreading抽象基类。在这种情况下,“创建”方法的定义变为:

template <class S>
BaseSpreading<S>* BaseSpreading<S>::create(std::string type) {
if (type == "tent") {
TentSpreading tent(-1, 1, 0);
IterativeMapSpreading<TentSpreading> map(tent);
return new BaseSpreading<IterativeMapSpreading<TentSpreading> >(map);
}
return NULL;
}

此代码的问题在于,我不再定义基类指针,因为它取决于模板参数S。例如,这是无效的:

BaseSpreading<S>* spreading;

这就是为什么我要问是否可以在BaseSpreading的定义中提供默认参数。即使能够指定默认模板参数,也无法在运行时切换模板参数,因为模板是在编译时由编译器实例化的,如 here所述。因此,似乎我无法避免使用虚函数,甚至在模板元编程的帮助下也是如此。我能想到的解决问题的唯一其他方法是通过函数指针,委派函数或使用函数编程来完全更改代码的设计...

最佳答案

如果我正确理解了所有这些内容,那么您希望基于内部循环中不会改变的内容进行动态调度,并且希望内部循环中不包含任何“if”语句或间接调度。这可以通过对代码进行小的重组来完成:

template<typename SPREADING>
void inner_loop(SPREADING* spreading) {
while(something_long) {
spreading->whatever();
}
}

main(){
if (opts.tentspreading) {
TentSpreading spreading(stuff);
inner_loop(&spreading);
} else {
IterativeMapSpreading spreading(other,stuff);
inner_loop(&spreading);
}
}

注意,两个inner_loop(&spreading)语句无法统一。实际上,它们使用不同的参数调用不同的函数。

关于c++ - 模板类的工厂模式和模板类的新类型默认参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11487648/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com