Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
148 views
in Technique[技术] by (71.8m points)

c++ - 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.

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;
  }
}

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);
}

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.

thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Building off Andrew's answer...

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.

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);
}

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.

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.

EDIT: 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;
}

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;
}

I haven't tested these; you might need a const or static in there.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...