17

我刚刚在关于条件运算符的维基百科文章中看到了这段代码:

Vehicle new_vehicle = arg == 'B' ? bus      :
                      arg == 'A' ? airplane :
                      arg == 'T' ? train    :
                      arg == 'C' ? car      :
                      arg == 'H' ? horse    :
                      feet;

我稍微更改了代码,但想法是一样的。你觉得这种条件运算符的用法可以接受吗?它比if-else结构简洁得多,并且使用开关肯定会为错误打开一系列全新的机会(任何人都失败了?)。此外,if- elses 并且switch不能用作 R 值,因此您必须首先创建变量,对其进行初始化,然后根据需要进行分配。

我真的很喜欢这个,但我想知道其他人的想法。

但是格式是必不可少的。

编辑:我还是喜欢这个。但我理解那些说“switch声明是为此而做出的”的人。好吧,也许是这样。但是如果条件是返回的函数调用bool呢?或者一百万其他你无法打开的东西。

你换恋人真的是想说服我一个巨大的if连锁店else更好吗?是的,不知道如何使用条件运算符的程序员不会理解这一点。他们应该学习如何使用它。这不是神秘的。

4

21 回答 21

33

我已经多次使用这种类型的结构。只要它的格式很好(即不是全部在一行上,使其不可读),我认为它没有问题。

于 2009-12-16T21:06:05.457 回答
31

我会使用开关,因为这是它的设计目的。是的,存在错误的风险,但是这个嵌套条件块被其他程序员误解的风险要高得多。

于 2009-12-16T21:05:24.223 回答
14

这是条件运算符使用的一个很好的例子。我在 C++、Java 和 Perl 中一直以这种方式使用它。

于 2009-12-16T21:07:59.690 回答
12

它不仅没有任何问题,而且以最简洁明了的方式传达了操作的意图。

替换为 if else 或 switch 构造需要代码段

"new_vehicle =  "

在每个实例中都重复,这要求读者阅读它的每个重复实例,以确保它实际上在每个实例中都是相同的。

于 2009-12-16T21:08:45.057 回答
11

我喜欢。它类似于 if-else-if 阶梯,只是更简洁。

于 2009-12-16T21:07:59.287 回答
11

字符常量周围有很多空格,这使得它有点难以阅读。我会在比较中加上括号:(并且可能会移动最后一个值。)

Vehicle new_vehicle = (arg == 'B') ? bus      :
                      (arg == 'A') ? airplane :
                      (arg == 'T') ? train    :
                      (arg == 'C') ? car      :
                      (arg == 'H') ? horse    :
                                     feet;

现在看起来很棒。

于 2009-12-16T23:27:35.867 回答
8

条件运算符版本干净、简单,任何了解 C 或 C++ 的人都可以立即明白发生了什么。它的另一个优点是它立即返回一个值,这意味着它可以放入初始化中(就像这个例子一样)。

switch 语句会更笨拙。它需要声明变量然后初始化,如果可以避免,通常是个坏主意。这将需要更多的输入,并且会有更多的地方让错误潜入。这不会那么清楚,因为有必要查看每个案例以查看它是否表示类似new_vehicle = foo; break;.

如果您只想在这里查找,那么有条件版本就很好,因为它会立即显示正在发生的事情。如果它会发生不止一次,请考虑将其放入一个函数中,以便在有任何变化时只有一个地方可以更新(例如,'R' 代表马车或 'L' 代表直升机)。

于 2009-12-16T21:37:47.853 回答
5

开关既更清晰,也可能更有效。如果我在代码审查中看到这样的代码,我会很担心。此外,这是“条件运算符”——它是三元运算符的一个实例(尽管目前是 C 和 C++ 中唯一的一个)。

于 2009-12-16T21:08:11.503 回答
5

纯粹是一种风格的选择。对于像您在这里展示的小型数据集,只要您的编程团队没有被这种事情所困扰,那么在我的书中就可以了。

于 2009-12-16T21:20:46.893 回答
5
Vehicle new_vehicle = getVehicleByType(arg);

Vehicle getVehicleByType(char arg){
  if (arg == 'B') return bus;
  if (arg == 'A') return airplane;
  if (arg == 'C') return car;
  if (arg == 'T') return train;
  if (arg == 'H') return horse;
  return feet;
}

我更喜欢这个。嵌套条件很聪明,但我认为这几乎同样简洁,不太可能让未来的读者感到困惑。对不起,如果语法关闭,我现在没有做太多 C 语言。

编辑:修正了评论中提到的返回类型遗漏。谢谢!

编辑:顺便说一句,我对你的版本并不感到害怕。当我看到它时,我没有惊呼 WTF 或 OMG。我只是更喜欢我的一点:)

于 2009-12-16T21:43:54.100 回答
3

我不是特别在意它。

它并没有真正购买任何东西,或者使任何事情变得更清楚,而且这是运营商的一种非常不标准的用法。

似乎主要优点是它有点聪明。我避免聪明,除非有一个很好的(外部)理由要聪明。

于 2009-12-17T07:19:59.083 回答
2

我倾向于使用 switch 语句,因为编译器会捕获重复的情况。可以说,这在此示例中不是问题,但如果列表变得非常长并且由多个不同的人处理,则很容易添加重复项而没有意识到它。

于 2009-12-16T21:33:12.857 回答
2

仔细阅读Wikipedia 文章的 C++ 部分。它明确列出了使用运算符是唯一选项的一些情况,?:不能用if/elseor代替switch

另一方面,我不会仅仅因为它看起来更漂亮而使用它。

于 2009-12-16T21:40:39.760 回答
1

我以前从未见过这样写的东西。虽然它很聪明且格式正确,但这似乎是使用字典/哈希表的绝佳机会(假设Vehicle是一个枚举,这还不清楚)。

于 2009-12-16T21:24:29.877 回答
1

一些人已经提到了使用一个std::map或其他关联数组类型来完成这项工作的可能性。只要您只在一个地方(或几个地方)这样做,您就可以考虑只使用普通数组或向量:

Vehicle vehicles[CHAR_MAX];

// Initialization    
std::fill_n(vehicles, CHAR_MAX, feet);
vehicles['A'] = airplane;
vehicles['B'] = bus;
vehicles['C'] = car;
vehicles['H'] = horse;
vehicles['T'] = train;

// Use
Vehicle new_vehicle = vehicles[arg];

根据您需要/使用的表的数量(存储相同类型的对象)以及所包含对象的大小(在本例中为车辆),这可能是std::map. 如果您要创建很多表,或者每个对象都很大,std::map则成为更合理的选择。

当您使用std::map(或unordered_map等)时,您正在使用更多代码来节省数据存储。这正好相反——但只要 Vehicle 很小(比如 4 个字节),像上面这样的一个表通常会占用大约 0.5 KB。很难准确猜测特定编译器的代码会有多大std::map,但它似乎通常会大于半千字节,所以如果你只创建一个这样的表,std::map可能是净亏损。

当然,如果你知道你只处理字母作为输入,你可以减少表格的大小:

template <class T>
class letter_table { 
    static const int range = 'Z' - 'A';

    T table[range];
public:
    // ...
    T operator[](int index) {
        index -= 'A';
        assert(index<range);
        return table[index];
    }
};

std::map在示例情况下,这将提供一个大约 100 字节的表——您可以在通常占用的空间中创建相当数量的 100 字节表。

于 2009-12-16T22:05:36.267 回答
1

纯实用:

另外: 三元序列更灵活,可以用来避免 的限制switch,您可以使用其他运算符(例如<=,>=)或任何其他测试,包括例如字符串比较。

x = IsEven(arg) ?  0 : 
    (arg < 0)   ? -1 : 1; // or whatever

此外,如果切换是性能瓶颈并且您的概率不均,则可以强制首先进行最可能的测试(由于未评估的未选择路径的保证)。

So-So 与 switch 语句不同,顺序很重要(除非你坚持使用==)。这可能是一个优势,但在其他方面类似于 switch,当维护者不熟悉这个概念或匆忙时,这可能会产生误导。

许多开发人员可能会回避,因为他们不确定细节(将评估哪些术语,操作员的要求是否可以?) - 但是,如果您的开发人员池无法掌握一个很好的示例,您可能有禁止三元运算符无法解决的问题。

减号 它不像 一样常见switch,因此优化器可能不会将其视为相同。优化器知道为开关选择最适合的实现(表、二分搜索、比较序列或任何组合)。优化器无法重新排列我们的评估顺序,并且不太可能支持此处的表查找。

需要良好的格式以便于识别(排列“?”和“:”) - 使用制表符时很糟糕。

美学

我喜欢它的精确和简洁,接近数学符号。但是,这也可以用来对付它。它可能会在代码审查中引起注意,因为它不太常见而且更脆弱。

于 2009-12-16T22:38:36.683 回答
1

只是为了比较,在 C++0x 中,您可以在不使用条件运算符或外联函数的情况下使用表达式:

Vehicle new_vehicle = [&]() -> Vehicle {
    if (arg == 'B') return bus;
    if (arg == 'A') return airplane;
    if (arg == 'T') return train;
    if (arg == 'C') return car;
    if (arg == 'H') return horse;
    return feet;
}();

不过,实际上并没有更好。

于 2009-12-16T22:46:20.723 回答
1

在我看来,由于示例的简单性,您所做的事情是可以接受的。如果您对每种情况都做更多的事情,这种类型的构造可能会很快变得混乱。出于这个原因,我更喜欢 switch 甚至嵌套 if then elses (如果没有太多情况),格式如下:

  if (A) {
      //Do A stuff
  }
  else if (B) {
      //Do B stuff
  }
  else if (C) {
      //Do C stuff
  }
  else {
      //Do default stuff
  }

它与代码的可读性有关,这有助于代码的可维护性。我从来都不是条件运算符的忠实粉丝,因为我不喜欢在一行中看到多个表达式。在调试器中单步执行代码时,条件运算符可能难以遵循。代码越简单,就越容易专注于代码在做什么。

于 2009-12-16T23:20:46.240 回答
1

怎么样:

enum Vehicle { bus = 'B', airplane = 'A', train, car = 'C', horse = 'H', feet = 'F' };
...
new_vehicle = arg;

:-), 顺便一提。

于 2009-12-17T01:05:16.453 回答
1

我认为它对编写代码的人很有用,但对于审稿人来说很难理解,

“保持简单的伙伴”

于 2009-12-17T07:32:02.553 回答
0

我们中的许多人已经习惯了各种报告工具中的 Iif 函数或 Excel 中的 If 函数,我们基本上需要使用不太清晰的 Iif(arg="B";"Bus";Iif(arg="A";飞机;“脚”))。与此相比,我更喜欢你的样品 :) 我个人会使用 if-else,但我不会对你的样品有任何问题。

于 2009-12-16T21:30:09.367 回答