C++ 在交换机的默认标签中放置什么?

C++ 在交换机的默认标签中放置什么?,c++,default,switch-statement,assert,C++,Default,Switch Statement,Assert,假设我有一个枚举 enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE}; 后来我有了这样一个函数: void Function (ShapeName const shape){ switch (shape){ case ShapeName::TRIANGLE: DoSomething1(); break; case ShapeName::CIRCLE:

假设我有一个枚举

enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE};
后来我有了这样一个函数:

void Function (ShapeName const shape){

    switch (shape){
        case ShapeName::TRIANGLE:
            DoSomething1();
            break;

        case ShapeName::CIRCLE:
            DoSomething2();
            break;

        case ShapeName::SQUARE: 
            DoSomething3();
            break;

        default:
            //THIS CODE BLOCK SHOULD NEVER BE EXECUTED!
    }

    return;
}
虽然不应执行默认标签,但我想说明如果程序员向“ShapeName”添加另一个值而未在开关中说明,可能会出现的潜在错误。
你建议我做什么?

1。断言
我可以用断言,但我在断言什么

assert(false); //?
2。例外情况
我可以抛出一个例外,但我认为这不是一个很好的做法。我的印象是,异常是针对由于某些环境而无法预测的运行时事件

3。退出
我可以立即退出程序并出错。 这感觉是最好的主意,但我不确定这是否是好的做法。我认为断言的优点是,当您准备好发布程序时,可以将它们全部关闭。然后,所有断言代码将不再存在



也许还有另一种我不知道的方式。我确实使用了一个编译器标志来警告未解释的值,但我仍然想知道其他人的建议。

我喜欢用信息性消息断言的想法。试试这个:

assert (!"The default case of so-so switch was reached.");
这总是返回false,但提供了一条您可以使用的消息

编辑:
我从记忆中找到了这个概念的来源;它在下面的书中:

C++编码标准——101条规则和准则

< P>我想,这将取决于剂量方法的作用。


如果以后它会导致不太优雅的崩溃,那么当调用它时,您一定要中断运行时,并解释“使用无效enum:enumName调用函数”或向开发人员发出通知,告知他们没有更新此switch语句,而不是让他们怀疑以后是否会出现故障。

我更喜欢这种特殊情况,即打开枚举标记并处理所有情况,即不使用默认值。这样,使用任何合理的编译器,如果有人将新标记添加到枚举而不是交换机,您将收到一条编译时警告,说明该标记未在交换机中处理。

简短回答:使用多态性来消除问题

长答覆: 解决根本问题(即如何防止switch语句中缺少条目?)的最简单方法是,如果有可能忘记条目,则避免使用switch语句。Switch语句在本地上下文中很有用,但是如果它们所表示的逻辑在多个位置重复,那么就有可能忘记更新一个语句,从而导致运行时错误

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();
}
switch语句在创建站点可能仍然有用:

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
}
enum类ShapeName:char{TRIANGLE,CIRCLE,SQUARE};
唯一的\u ptrMakeShape(ShapeName const Shape){
开关(形状){
案例ShapeName::三角形:
返回唯一的_ptr(新三角形());
case ShapeName::CIRCLE:
返回唯一的_ptr(新圆());
case ShapeName::SQUARE:
返回唯一的_ptr(新的正方形());
}
抛出std::runtime_error();
//或者从其他答案中选择你喜欢的选项
}
但这是唯一存在逻辑的地方。甚至可以通过静态多态性来改进:

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
}
enum类ShapeName:char{三角形、圆、正方形、椭圆};
模板
独特的_ptrMakeShape();
模板
独特的_ptrMakeShape()
{
返回唯一的_ptr(新三角形());
}
模板
唯一的\u ptrMakeShape()
{
返回唯一的_ptr(新圆());
}
模板
独特的_ptrMakeShape()
{
返回唯一的_ptr(新的正方形());
}
int main()
{
MakeShape();//好的
MakeShape();//编译错误
}

有关更多信息,请参阅。

4。你能告诉你的编译器为此发出警告吗?这是我对旧式枚举所期望的一个选项。@SteveJessop g++-w-Wall-Wextra-Wswitch-Wswitch-default-Wswitch-enum-std=c++0x-o main.cpp奇怪的是,上面的代码没有给我任何警告。我添加了另一个ShapeName并去掉了默认标签。还是没什么!胡扯。C++11的实现还没有完成,所以我们可以满怀希望。可能是重复的,或者如果您不喜欢它的拼写方式,
assert(false&&“message”)assert(不“可达”)显然,对于新的C++11枚举类,GCC是不合理的,尽管提问者没有说明GCC的版本。@SteveJessop GCC(Ubuntu/Linaro 4.6.1-9ubuntu3)4.6。1@SteveJessop:gcc(尝试了4.4.5、4.5.2和4.6.3)给出“
警告:枚举值‘其他’未在开关中处理”
”如果我删除默认值并添加一个
OTHER
标记…为什么要投反对票?我认为对于这个人为的例子来说,这是最好的解决办法。Switch语句可能是一种代码味道,正是出于这个原因。
default
的问题是,对于省略的情况,您不会得到编译器警告;如果您处于每种情况都返回的开关类型(例如,工厂),编译器将抱怨函数末尾缺少返回。我认为MSVC曾经有一个无法访问的宏来帮助我们。