【问题标题】:Ternary expression which "does nothing" (noop) if the condition is false?如果条件为假,则“什么都不做”(noop)的三元表达式?
【发布时间】:2013-10-15 05:53:06
【问题描述】:

出于好奇,我开始想知道是否有可能有一个三元表达式,如果它的计算结果为 false,则在 false 分支中什么也不做。

即有没有办法这样写:

variable = (someBool) ? i : <do nothing>;

相对于:

if (someBool) {
    variable = i;
}

我尝试将((void)0)while(false){}; 作为无操作,但编译器需要一个表达式。

更新:

我意识到这个问题失去了一些意义,因为我试图让代码更简单。我最初的想法是用三元初始化一个静态变量 - 使用静态变量本身作为条件:

static int var = (var != 0) ? var = 1 : (var already initialized, do nothing);

这是假设未初始化的变量被初始化为 0,这并不总是正确的(或者在发布版本中永远不会,不太确定)。所以也许这是一个假设性问题。

【问题讨论】:

  • 如果变量是静态的,那么这个问题没有任何意义。因为在任何版本的 C 标准中,具有静态存储持续时间的变量的初始化表达式必须始终是常量表达式。此外,在任何版本的 C 标准中,静态存储持续时间变量总是初始化为 0。
  • 赋值和初始化在 C 中实际上是两个不同的东西,静态变量的初始化器只在所有代码执行之前进行评估。
  • (C++也是如此)
  • 实际上,不,他们不是。在 C++ 中,静态存储持续时间的变量的初始化表达式可以是任何东西,只要它本身已被初始化。例如。 rand() 可以,虽然可能没有种子。

标签: c++ objective-c c ternary-operator


【解决方案1】:

short-circuit 怎么样?

int variable = 0;
bool cond = true; // or false

(cond && (variable = 42));

printf("%d\n", variable);

【讨论】:

  • 这是迄今为止解决 OP 要求的唯一答案。 +1。
  • 标签中的语言之一是 C#。这在 C# 中是无效的(不仅仅是因为 printf)。
  • 有趣的方法,奇怪的结构,但令人惊讶的是编译器喜欢它(从标签中删除了 C#,它并不真正属于那里,我使用的是 Objective-C,所以 C/C++ 也应该可以工作,但不是C#)
  • @DeeMac:printf 在 C# 中不起作用,但其余的应该没问题
  • @DeeMac:哦,是的,完全误读了那部分。无论如何,我仍然认为if(cond) variable = 42; 更好。篇幅够短,可读性强,容易理解
【解决方案2】:

这个怎么样:

variable = (someBool) ? i : variable ;

虽然我个人更喜欢原来的 if 语句

【讨论】:

  • 好点,但在我的特殊情况下(我简化了显然失去意义的代码)我尝试初始化一个静态变量,编译器说“在它自己的初始化中可疑使用静态变量”或其他东西为此
  • @LearnCocos2D 编译器是对的。如果你要初始化一个静态变量,你不能在赋值之前读取它的值。
  • 我知道,那是我开始怀疑的时候。 ;) 特别是因为表达式是: static int var = (var != 0) ? var = 1 : (var 已经初始化,什么都不做);
  • @DavidSchwartz:我很确定您可以读取它的值,因为静态对象在初始化之前是 0 初始化的。不记得这只是在文件和类范围内,还是在函数范围内。
【解决方案3】:

编译器不仅期望表达式,还期望在左侧返回type 的表达式(variable 的类型无论如何)。所以,不,你不能那样做。不是条件执行,而是variable成员赋值。

这些是完全不同的东西。 在第二个例子中:

if (someBool) {
    variable = i;
}

您不分配任何内容,而只是根据条件执行。所以在你的的情况下,你不想任何事情(而不是assign任何事情),要走的路是条件执行,所以使用只是第二种情况。

【讨论】:

  • 为什么编译器会期望 OP 的问题中的任何内容返回布尔值? ?: 表达式的返回类型是第二个和第三个操作数的类型(第二个和第三个相互平衡)。
  • @Lundin:好点,我错误地验证了 OP 的代码。更正答案以满足更准确提供的问题。
【解决方案4】:

conditional expression的格式是

<expression> ? <expression> : <expression>

换句话说,它必须有某种表达方式。

【讨论】:

  • 这实际上并没有回答这个问题。例如。在 C++ 中,任何表达式都可能抛出,这不会初始化左侧。
  • @MSalters 我在更新之前发布了这个答案。但是即使表达式抛出,也必须有 some 表达式才能编译代码。
  • 是的,但可以是throw-expression,即true ? throw 1 : "Foo"
  • @MSalters 嗯。不知道 throw 可能是 C++ 中的表达式。
【解决方案5】:

解决您的编辑问题:在 C99 中,静态范围的变量被初始化为 0。但是,我从来没有真正相信过这一点,因为自 K&R 时代以来我一直在使用 C 进行编程。

无论如何,只需初始化变量。由于变量是静态的,它只会在程序的整个执行时间内发生一次。

【讨论】:

  • 类似:static int var = someComplexFunction();只会执行一次复杂的功能吗?即使在函数范围内(与全局范围相反)也能保证这一点吗?我的意思是静态是静态的,如果函数只运行一次就有意义。
  • @LearnCocos2D:在单线程程序中保证,多线程存在潜在的竞争条件。当在 C++11 和 C11 中引入线程时,我不记得是否保证了静态的线程安全初始化,但是(a)你的代码无论如何都不是线程安全的,所以并不比依赖执行; (b) 在 C11 和 C++11 之前,一些实现进行了线程安全初始化,而另一些则没有,但它们通常记录了它是什么,所以你可以找出来。
  • @LearnCocos2D 在 C99 中 static int var = someComplexFunction(); 将是非法的。静态的初始化器必须是常量表达式或字符串文字。这使得线程安全性毫无意义。
  • @SteveJessop “当 C++11 和 C11 中引入线程时,我不记得是否保证了静态的线程安全初始化” - 它是,按照标准(当然,这仍然没有说明主要编译器的实际支持)。
【解决方案6】:

你可以这样做:

variable = !someBool ?: i;

因为 ?: 在 if 表达式为真时将无操作,但如果为假则分配 i。

注意:这只在 Obj-C 中测试过

【讨论】:

    【解决方案7】:

    怎么样

    (someBool) ? (variable = i) : NULL;
    

    【讨论】:

    • @self。是的,假设变量是intideone.com/2urC8Hideone.com/lYz1dV
    • 我也会投反对票,因为它不是“有效的 C”,而是 UB C。如果你写 variable = (someBool) ? (variable = i) : NULL;,你会调用未定义的行为。在对控制表达式求值之后有一个序列点,但随后您执行variable = (variable = i)。变量被修改两次,中间没有序列点,左侧和右侧相对于彼此是无序的。此外,您只能将 NULL 作为第三个参数,因为 NULL 的计算结果为整数值 0,即使理智要求 NULL 只能与指针一起使用。
    • @Lundin 虽然你对第三个操作数的看法是有道理的,但我还没有看到答案写成variable = (someBool) ? (variable = i) : NULL;,这确实是一派胡言。
    • @ChristianRau 因为使用 ?: 运算符的唯一情况是您想要对某事物进行单行赋值。在所有其他情况下, ?: 运算符只是添加了混淆。当您可以编写可读代码时,为什么还要编写不可读的东西? “C 语言允许它”是你能给出的最蹩脚的借口,因为 C 不是一种理性、理智的语言。
    • @Lundin “因为使用 ?: 运算符的唯一情况是当您想要对某物进行单行赋值时。在其他情况下,仅使用 ?: 运算符添加混淆。” - 当然,是的。然而,这并不能验证您错误地假设答案确实“唯一有意义的情况”中使用它的评论
    【解决方案8】:

    对于 C# 说: 语法:

    condition ? first_expression : second_expression;
    

    它说的是 first_expression 和 second_expression:

    first_expression 和 second_expression 的类型必须相同,或者必须存在从一种类型到另一种类型的隐式转换。

    【讨论】:

    • 谁说过 C#? And it says...谁说的?
    • @Lundin “谁说过 C#?” - 早期版本中的问题。
    【解决方案9】:

    如果您要评估可空对象类型而不是 bool,您总是可以这样写:

    variable = myVar ?? i;
    

    Hacky/cluudgey/imractical - 可能所有 3 个,但为了这个问题,这是一种省略“else”的方式。

    【讨论】:

      【解决方案10】:

      尝试:null lambda。

      auto null_lambda = [](){return;};
      int a = 1;
      int b = 2;
      vector<int> c;
      
      a > c ? b = c.push_back(b) : null_lambda();
      

      【讨论】:

        猜你喜欢
        • 2012-11-20
        • 1970-01-01
        • 2017-03-08
        • 2020-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-05
        • 1970-01-01
        相关资源
        最近更新 更多