【发布时间】:2018-09-27 06:07:02
【问题描述】:
假设“标准”C++ 继承范式:
struct GeneralFunc
{
/*..members..*/
virtual double value(double a, double b) { return 0; }
};
struct Func_classA : GeneralFunc
{
/*..members..*/
double value(double a, double b) { return a * b; }
};
struct Func_classB : GeneralFunc
{
/*..members..*/
double value(double a, double b) { return a + b; }
};
void main(){
double a = 1.0, b = 1.0;
std::vector<GeneralFunc*> my_functions;
//fill my_functions from input
for (auto& f : my_functions)
{
double v = f->value(a, b);
}
}
我想要一个对迭代最有效的实现,即最小化间接引用、最大化内联优化等。为了限制问题,我事先知道我想要实现的每个特定“类型”(我可以只定义我需要的“func”类型,而不必允许其他可能性)。
出现几个可用的选项:
boost::polycollection
#include <boost/poly_collection/base_collection.hpp>
//...rest the same
boost::base_collection<GeneralFunc> my_functions
//...rest the same
std::variant
#include <variant>
//...rts
using funcs = std::variant<Func_classA, Func_classB /*..possibly more../*>
std::vector<funcs> my_functions
或 CRTP (Curiously Recurring Template Pattern)
让我知道正确的命名法,但在这里我根据“类型”“向上转换”基类——一种手动调度。
template<typename T>
struct GeneralFunc
{
/*..members..*/
int my_type;
double value(double a, double b) {
switch (my_type){
case TYPE_A:
return static_cast<Func_classA*>(this)->value(a,b);
/*..you get the idea..*/
我可以牺牲边际效率来简化开发,但是对于这种情况下的“最佳实践”是否有共识?
EDITS* 修正了一些错别字;我目前的开发是 CRTP 最后一个选项的“开发中”。
解决方案:
经过测试,boost::polycollection 和 std::variant 都是有效的方法。然而,事实证明这是最有效的(根据记忆,可能略有偏差)。
enum ftype { A = 0, B, C };
struct GeneralFunc
{
ftype my_type;
GeneralFunc(ftype t) : my_type(t) {}
inline double value(double a, double b) const; // delay definition until derived classes are defined
}
struct Func_classA : GeneralFunc
{
Func_classA() : GeneralFunc(ftype::A) {}
inline double value(double a, double b) const { return a * b; }
}
/* define B, C (& whatever) */
inline double GeneralFunc::value(double a, double b)
{
switch(my_type){
case (ftype::A):
return static_cast<Func_classA*>(this)->value(a,b);
/* same pattern for B, C, ect */
}
}
void main(){
std::vector<std::unique_ptr<GeneralFunc>> funcs;
funcs.push_back(std::make_unique<Func_classA>());
funcs.push_back(std::make_unique<Func_classB>());
funcs[0]->value(1.0,1.0); // calls Func_classA.value
funcs[1]->value(1.0,1.0); // calls Func_classB.value
}
【问题讨论】:
-
你在你的基类中错过了 virtual
-
通常会有其他约束导致一种或另一种设计。我认为您的原始解决方案已经非常理想。但是您可以将基类中的函数定义为
pure virtual(至少应该是virtual)。而且,顺便说一句,您的最后一个示例不是 CRTP。 -
最后,如果您关心的是速度/效率,那么标准答案是:实施,衡量!
-
什么是 CTRP?是 CRTP 吗?
-
为了我的钱,如果可能的话,我会选择变体。
标签: c++ boost std-variant