使用模板而不是开关 [英] Using template instead of switch
问题描述
我想在我的代码中执行一组类似的测试,但只根据一个参数改变。
I want to perform a set of tests in my code that are similar but change only depending on a parameter.
我可以使用switch语句写: / p>
I could write this using a switch statement:
bool doTest(EnumSensorFamily family, const StructSensorProposal& proposed)
{
switch (family)
{
case FAM1:
return (ExpectedFam1 == proposed.Fam1SensorId);
break;
case FAM2:
return (ExpectedFam2 == proposed.Fam2SensorId);
break;
case FAM3:
return (ExpectedFam3 == proposed.Fam3SensorId);
break;
default:
ERROR ("Unexpected family");
return false;
}
}
我想要用模板专门化p>
I was thinking of doing this with template specialisations
template <EnumSensorFamily family>
bool doTest(const StructSensorProposal& proposed);
template<>
bool doTest<FAM1> (const StructSensorProposal& proposed)
{
return (ExpectedFam1 == proposed.Fam1SensorId);
}
template<>
bool doTest<FAM2> (const StructSensorProposal& proposed)
{
return (ExpectedFam2 == proposed.Fam2SensorId);
}
template<>
bool doTest<FAM3> (const StructSensorProposal& proposed)
{
return (ExpectedFam3 == proposed.Fam3SensorId);
}
除了避免switch语句包含near
Is there any benefit of doing this apart from avoiding a switch statement containing near identical cases?
我希望能够编写单一方法以减少维护开销。
Ideally I would like to be able to write single method to reduce the maintenance overhead.
推荐答案
建立安德鲁的回答...
Building off Andrew's answer...
EnumSensorFamily family
必须在编译时已知。如果直到运行时才知道,那么你必须写一个开关
来选择模板,让你回到你开始的地方。
Note that the EnumSensorFamily family
must be known at compile time. If it is not known until run time, then you'll have to write a switch
to choose the template, putting you back where you started.
另一种方法是使用Traits模式:
Another way to do this is with the Traits pattern:
template <EnumSensorFamily family>
struct SensorTraits;
template <>
struct SensorTraits<FAM1>
{
const EnumSensorFamily kFamilyID = ExpectedFam1;
};
template <>
struct SensorTraits<FAM2>
{
const EnumSensorFamily kFamilyID = ExpectedFam2;
};
template <>
struct SensorTraits<FAM3>
{
const EnumSensorFamily kFamilyID = ExpectedFam3;
};
template <EnumSensorFamily family>
bool doTest(const StructSensorProposal& proposed)
{
return (SensorTraits<family>::kFamilyID == proposed.Fam1SensorId);
}
如果您尝试使用 doTest
与缺乏traits专业化的传感器家族,你得到一个编译错误。还要注意,你永远不会实例化一个traits对象,你只需使用它的定义。
If you try to use doTest
with a sensor family that lacks a traits specialization, you get a compile error. Also note that you never instantiate a traits object, you just use its definitions.
这允许你重复使用常量,typedef,无论在几个函数。此外,添加一个新的家庭不涉及梳理所有的代码,寻找每个开关
关心的语句。您需要做的是创建一个新的 SensorTraits
专业化。
This lets you reuse constants, typedefs, whatever in several functions. Additionally, adding a new family does not involve combing through all the code looking for every switch
statement that cares. All you have to do is create a new SensorTraits
specialization.
编辑:可以使该字段依赖于传感器系列,并具有指向成员的指针: / p>
You can make the field dependent on the sensor family with a pointer to member:
template <>
struct SensorTraits<FAM1>
{
const EnumSensorFamily kFamilyID = ExpectedFam1;
int StructSensorProposal::*proposalField = &StructSensorProposal::fam1field;
};
// ...
template <EnumSensorFamily family>
int getProposedField(const StructSensorProposal& proposed)
{
return proposed.*SensorTraits<family>::proposalField;
}
你也可以放入一个 typedef
传感器的数据类型:
You can also put in, say, a typedef
for the sensor's data type:
template <>
struct SensorTraits<FAM1>
{
const EnumSensorFamily kFamilyID = ExpectedFam1;
typedef uint16_t data_type;
data_type StructSensorProposal::*proposalField = &StructSensorProposal::fam1field;
};
// ...
template <EnumSensorFamily family>
SensorTraits<family>::data_type getProposedField(const StructSensorProposal& proposed)
{
return proposed.*SensorTraits<family>::proposalField;
}
您可能需要 const
或 static
。
这篇关于使用模板而不是开关的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!