我已经将我遇到的模板专业化使用的两个代码摘录放在一起,我觉得特别奇怪。我甚至会不必要地称他们浮华。
总的来说,我怀疑模板实际上是设计这些对象的最佳方式(尤其是第一种情况)。
哪种方法更好,为什么?或者有一种完全不同的方法更好吗?
1)模板作为函数传递指针的替代:
//fusion_manager.h
template <typename InputFilterAlgorithm,
typename PredictionAlgorithm,
typename AssociationAlgorithm,
typename FusionAlgorithm>
class FusionManager
{
public:
FusionManager(Environment& env);
...
private:
Environment& env_m;
InputFilterAlgorithm filter_alg_m;
PredictionAlgorithm prediction_alg_m;
AssociationAlgorithm association_alg_m;
FusionAlgorithm fusion_alg_m;
...
};
//fusion_manager.cpp
template <typename InputFilterAlgorithm,
typename PredictionAlgorithm,
typename AssociationAlgorithm,
typename FusionAlgorithm>
FusionManager<InputFilterAlgorithm,
PredictionAlgorithm,
AssociationAlgorithm,
FusionAlgorithm,
TrackExtendedDataType>::FusionManager(Environment& env)
:
env_m(env),
filter_alg_m(env),
prediction_alg_m(env),
association_alg_m(env),
fusion_alg_m(env)
{
...
}
//main.cpp
...
FusionManager<TestInputFilterAlgorithm,
TestPredictionAlgorithm,
TestAssociationAlgorithm,
TestFusionAlgorithm> fusionManager(env);
...
......而不是使用这样的东西:
//fusion_manager.h
class FusionManager
{
public:
//Let's say each algorithm is encapsulated by a class
FusionManager(Environment& env,
InputFilterAlgorithm&&,
PredictionAlgorithm&&,
AssociationAlgorithm&&,
FusionAlgorithm&&);
private:
Environment& env_m;
InputFilterAlgorithm filter_alg_m;
PredictionAlgorithm prediction_alg_m;
AssociationAlgorithm association_alg_m;
FusionAlgorithm fusion_alg_m;
};
//fusion_manager.cpp
FusionManager::FusionManager(Environment& env,
InputFilterAlgorithm&& filter_alg,
PredictionAlgorithm&& prediction_alg,
AssociationAlgorithm&& association_alg,
FusionAlgorithm&& fusion_alg)
:
env_m(env),
filter_alg_m(std::move(filter_alg)),
prediction_alg_m(std::move(prediction_alg)),
association_alg_m(std::move(association_alg)),
fusion_alg_m(std::move(fusion_alg))
{
...
}
//main.cpp
...
FusionManager<TestInputFilterAlgorithm,
TestPredictionAlgorithm,
TestAssociationAlgorithm,
TestFusionAlgorithm> fusionManager(env);
...
2)使用模板替代继承和虚拟方法:
//factorization.h
template<typename ProbabilityDistributionType>
class Factorization
{
...
public:
ProbabilityDistributionType factorize();
private:
std::Vector<ProbabilityDistributionType> factors_m;
...
};
//factorization.cpp
template<>
CPD Factorization<CPD>::factorize()
{
for (auto & factor : factors_m)
{
factor.factorize();//This will call the factorize method of CPD
}
}
template<>
JointProbDistr Factorization<JointProbDistr>::factorize()
{
for (auto & factor : factors_m)
{
factor.factorize();//This will call the factorize method of JointProbDistr
}
}
而不是使用这样的东西:
//factorization.h
template<typename ProbabilityDistributionType>
class Factorization
{
...
public:
virtual ProbabilityDistributionType factorize() = 0;
private:
std::Vector<ProbabilityDistributionType> factors_m;
...
};
//cpd_factorization.h
class CPDFactorization : public Factorization<CPD>
{
...
public:
CPD factorize();//Implementing the parent's pure virtual method. This will call the factorize method of CPD
};
//jointprobdistr_factorization.h
class CPDFactorization : public Factorization<JointProbDistr>
{
...
public:
JointProbDistr factorize();//Implementing the parent's pure virtual method. This will call the factorize method of JointProbDistr
};
答案 0 :(得分:4)
使用模板既有优点也有缺点,编译器可以看到使用模板的完全专用的实现。
这是一个优势,因为它允许编译器更积极地进行优化:它可以根据需要内联,并解决函数调用之间的任何数据移位,消除程序员可能已经引入的所有错误。努力以方便的方式构建他们的源代码。
这是一个缺点,因为它迫使模板化决策成为编译时决策。如果变量是模板参数,则它不能依赖于在运行时给出的输入。想象一下如果std::string
的长度是模板参数会发生什么:字符串操作与FORTRAN一样灵活。你绝对不想要这个。当然,在编译时应该知道一些事情,将它们作为模板参数是非常好的。但是如果你过度使用模板,就会得到不必要的严格代码。 (在那里,完成了,学会了避免它。)
这也是一个缺点,因为它强制在实现更改时重新编译模板的所有用法。如果你的程序是除main之外的所有模板,你必须为每一个小改动重新编译一切。如果使用指向函数,虚函数和/或函子的指针,则在调用函数的实现发生更改时,不需要重新编译调用站点。在正确设置的构建系统中,它们将依赖于不会发生变化的标题,除非有破坏的界面变化。对我来说,其结果是,我的所有模板都应该是小的,自包含的代码,不依赖于多个层中的其他模板。
总而言之,模板是一个很好的工具,同时也是一个非常容易被滥用的工具。当你从中获得任何真正的优势时,尽量不要使用它们。
答案 1 :(得分:3)
第一个可用于任何可调用的函数 - 函数指针std::function
等。
你的建议类型非常有限。
第二种方法避免了虚拟调用,这在您想要避免虚拟调用的情况下非常有用,并为内联提供了更多机会。
简而言之:第一个使用模板进行灵活性,第二个使用性能。