如何重写C++代码的复杂行(嵌套三元运算符) - c#

我一直在浏览其他人的代码以进行调试,结果发现:

!m_seedsfilter ? good=true : m_seedsfilter==1 ? good=newClusters(Sp) : good=newSeed(Sp);  

这是什么意思?是否有自动化工具可以使if / else语句更易于理解?处理此类复杂控制结构的任何技巧?

编辑说明:我将标题中的“不必要的复杂”更改为“复杂”,因为这是出于意见的考虑。到目前为止,感谢您的所有回答。

参考方案

如果重写如下,则可以改善所编写的语句。

good = m_seedsfilter==0 ? true :
       m_seedsfilter==1 ? newClusters(Sp) :
                          newSeed(Sp);

...但是总的来说,您应该熟悉三元声明。最初发布的代码,xanatos的版本或我的代码都没有本质上的邪恶。三元声明不是邪恶的,它是该语言的基本功能,一旦您熟悉了它们,您会注意到,这样的代码(如我所发布的,而不是您的原始文章所写的)实际上更容易比一串if-else语句阅读。例如,在此代码中,您可以简单地阅读以下语句:“变量good等于...如果是m_seedsfilter==0,则是true,否则,如果是m_seedsfilter==1,则是newClusters(Sp),否则,是newSeed(Sp)。”

请注意,我的上述版本避免了对变量good的三个单独的赋值,并且很清楚,该语句的目标是为good赋值。同样,以这种方式编写的代码可以清楚地看出,这实质上是一个“切换案例”构造,默认情况下为newSeed(Sp)

应该注意的是,只要不覆盖operator!()类型的m_seedsfilter,我的上面的重写就很好。如果是这样,那么您必须使用它来保留原始版本的行为...

good = !m_seedsfilter   ? true :
       m_seedsfilter==1 ? newClusters(Sp) :
                          newSeed(Sp);

...并且正如xanatos在下面的评论所证明的,如果您的newClusters()newSeed()方法返回的类型彼此不同,并且如果这些类型是使用精心设计的无意义的转换运算符编写的,那么您将必须还原为原始代码本身(尽管希望格式可以更好,例如xanatos自己的帖子),以便忠实地复制与原始帖子完全相同的行为。但是在现实世界中,没有人会这样做,所以上面的第一个版本应该没问题。

原始帖子/答案后两年半的更新:
有趣的是,我和@TimothyShields有时会不断对此表示反对,而Tim的回答似乎始终如一地跟踪该回答的大约50%(截至此更新,为43比22)。

我以为我会再添加一个示例,说明明智使用时三元语句可以增加的清晰度。下面的示例是我为一个调用栈使用分析器(分析编译的C代码的工具,但该工具本身是用C#编写)编写的代码的简短摘要。至少就外部可见效果而言,所有这三种变体都实现了完全相同的目标。

1.不带三元运算符:

Console.Write(new string(' ', backtraceIndentLevel) + fcnName);
if (fcnInfo.callDepth == 0)
{
   Console.Write(" (leaf function");
}
else if (fcnInfo.callDepth == 1)
{
   Console.Write(" (calls 1 level deeper");
}
else
{
   Console.Write(" (calls " + fcnInfo.callDepth + " levels deeper");
}
Console.WriteLine(", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");

2.使用三元运算符,分别调用Console.Write():

Console.Write(new string(' ', backtraceIndentLevel) + fcnName);
Console.Write((fcnInfo.callDepth == 0) ? (" (leaf function") :
              (fcnInfo.callDepth == 1) ? (" (calls 1 level deeper") :
                                         (" (calls " + fcnInfo.callDepth + " levels deeper"));
Console.WriteLine(", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");

3.使用三元运算符,折叠为对Console.Write()的单个调用:

Console.WriteLine(
   new string(' ', backtraceIndentLevel) + fcnName +
   ((fcnInfo.callDepth == 0) ? (" (leaf function") :
    (fcnInfo.callDepth == 1) ? (" (calls 1 level deeper") :
                               (" (calls " + fcnInfo.callDepth + " levels deeper")) +
   ", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");

有人可能会争辩说,上面三个示例之间的区别是微不足道的,并且由于它是微不足道的,为什么不喜欢更简单的(第一个)变体?一切都是为了简洁;用“尽可能少的单词”表达一个想法,以便听者/阅读者在我到达想法结束时仍能记住想法的开始。当我和小孩说话时,我会使用简单,简短的句子,结果需要更多的句子来表达一个想法。当我与能说一口流利英语的成年人交谈时,我会使用更长,更复杂的句子,以更简洁地表达想法。

这些示例将一行文本打印到标准输出。尽管它们执行的操作很简单,但应该容易想象它们是较大序列的子集。我越清楚地表达该序列的子集,该序列就越适合我的编辑器屏幕。当然,我可以轻易地将这种努力付诸东流,从而更难以理解。目标是在易于理解和简洁之间找到“sweet spot”。我认为,一旦程序员熟悉三元语句,使用它们的代码就会比不使用三元语句的代码变得容易(例如,上面的 2 3 ,而上面的 1 )。

有经验的程序员应该对使用三元语句感到满意的最终原因是避免在进行方法调用时创建不必要的临时变量。作为示例,我给出了上述示例的第四个变体,其逻辑浓缩为对Console.WriteLine()的单次调用;结果是可理解的 简洁:

4.不带三元运算符,折叠为对Console.Write()的单个调用:

string tempStr;
if (fcnInfo.callDepth == 0)
{
   tempStr = " (leaf function";
}
else if (fcnInfo.callDepth == 1)
{
   tempStr = " (calls 1 level deeper";
}
else
{
   tempStr = " (calls " + fcnInfo.callDepth + " levels deeper";
}
Console.WriteLine(new string(' ', backtraceIndentLevel) + fcnName + tempStr +
                  ", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");

在争论“将逻辑浓缩为对Console.WriteLine()的单次调用是不必要的”之前,请考虑这仅是一个示例:想象对其他方法的调用,该方法需要多个参数,所有这些方法都需要基于其他变量状态的临时变量。您可以创建自己的临时变量,并使用这些临时变量进行方法调用,也可以使用三元运算符,然后让编译器创建自己的(未命名的)临时变量。我再次指出,三元运算符使代码更简洁,更易理解。但是要使它易于理解,您必须放弃所有三元运算符是邪恶的先入为主的观念。

在Java中,执行“ ++++++++”表达式,编译器未报告任何错误并且可以正确执行? - java

我用eclipse编写了这段代码,用war写过,结果为3d。public static void main(String[] args) { double a = 5d + + + + + +-+3d; System.out.println(a); } 参考方案 您的表情可以改写为(5d) + (+ + + + +-+3d) 其中第一个+是应用于两个操作数的…

在Python和C++之间传输数据而无需写入Windows和Unix文件 - python

我有预先存在的python和C ++文件,其中python文件定义了许多点,而C ++代码利用其现有库进行了所需的计算。最终产品是C ++代码写入的文件。我正在寻找一种在python中获取2000点列表的方法,将其传递给函数,然后执行所有C ++代码并输出我需要的文件。其他注意事项。这必须是可以在Linux或Windows机器上工作的东西,并且最少安装新插件…

Java值加变量++ - java

考虑以下代码int val1 = 3; val1++; int val2 = val1++; System.out.println(val1); System.out.println(val2); Val1值= 5;Val2值= 4;为什么Val1的值是“ 5”?据我了解,应该为4,因为:在第1行,它的赋值为3,在第2行,通过val1 ++加上1,结果val…

如何锁定终端运行的perl,obj c,c++,python和ruby等脚本的源代码? - python

我想出售我在perl,obj c,c ++,python,ruby,bash,php等中制作的脚本等它们都在终端中运行。 (Linux)如何锁定源代码,以便无需人们访问源代码即可分发我的脚本..?换句话说,如何将在Terminal中运行的程序的源代码锁定,以便人们可以使用该程序(如果该代码已下载到他们的Linux机器上,但他们无法访问实际的源代码)?例:ex…

在C++之后学习C# - c#

随着语言的发展,我一直在学习C和C++。现在,我想学习C#。我知道它们之间有一些巨大的差异-例如删除指针和垃圾回收。但是,我不知道两者之间的许多差异。C++程序员在转移到C#时需要知道的主要区别是什么? (例如,我可以使用什么代替STL,它们之间的语法差异或任何其他可能被认为重要的东西。) 参考方案 C# for C++ Developers是一个不错的起点…