Short answer: Use polymorphism to eliminate the problem.
Long answer:
The easiest way to solve the root problem (i.e. How to prevent switch statements with missing entries?) would be to avoid using switch statements if there's a chance of entries being forgotten. Switch statements are useful in local contexts, but if the logic they represent is duplicated in multiple locations then there's a possibility of forgetting to update one and you're setting yourself up for runtime errors.
class Shape
{
// functionality MUST be added for new shape types
// or a compile error will occur
virtual void DoSomething() const = 0;
};
void Function (Shape const & shape){
return shape.DoSomething();
}
The switch statement may still be useful at the site of creation:
enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE};
unique_ptr< Shape > MakeShape (ShapeName const shape){
switch (shape){
case ShapeName::TRIANGLE:
return unique_ptr< Shape >( new Triangle() );
case ShapeName::CIRCLE:
return unique_ptr< Shape >( new Circle() );
case ShapeName::SQUARE:
return unique_ptr< Shape >( new Square() );
}
throw std::runtime_error();
// or whichever option you prefer from the other answers
}
But that's the only place the logic exists. And even that can be improved upon with static polymorphism:
enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE,ELLIPSE};
template< ShapeName shape >
unique_ptr< Shape > MakeShape();
template<>
unique_ptr< Shape > MakeShape< ShapeName::TRIANGLE >()
{
return unique_ptr< Shape >( new Triangle() );
}
template<>
unique_ptr< Shape > MakeShape< ShapeName::CIRCLE >()
{
return unique_ptr< Shape >( new Circle() );
}
template<>
unique_ptr< Shape > MakeShape< ShapeName::SQUARE >()
{
return unique_ptr< Shape >( new Square() );
}
int main()
{
MakeShape< ShapeName::TRIANGLE >(); // okay
MakeShape< ShapeName::ELLIPSE >(); // compile error
}
See Martin Folwer for more info.