C# 如何重写C++;代码(嵌套三元运算符)
为了进行调试,我一直在查看其他人的代码,发现如下:C# 如何重写C++;代码(嵌套三元运算符),c#,c++,c,C#,C++,C,为了进行调试,我一直在查看其他人的代码,发现如下: !m_seedsfilter ? good=true : m_seedsfilter==1 ? good=newClusters(Sp) : good=newSeed(Sp); 这是什么意思?是否有一个自动工具可以将其转换为更易于理解的if/else语句?处理像这样复杂的控制结构有什么建议吗 编辑注:我将标题中的“不必要的复杂”改为“复杂”,因为这是一个意见问题。谢谢你迄今为止的所有答案。这样更好吗 !m_seedsfilter ? go
!m_seedsfilter ? good=true : m_seedsfilter==1 ? good=newClusters(Sp) : good=newSeed(Sp);
这是什么意思?是否有一个自动工具可以将其转换为更易于理解的if/else语句?处理像这样复杂的控制结构有什么建议吗
编辑注:我将标题中的“不必要的复杂”改为“复杂”,因为这是一个意见问题。谢谢你迄今为止的所有答案。这样更好吗
!m_seedsfilter ? good=true
: m_seedsfilter==1 ? good=newClusters(Sp)
: good=newSeed(Sp);
我要补充一点,虽然理论上可以简化这个表达式(为什么?这太清楚了!),但得到的表达式可能不会在所有可能的情况下都是100%等价的。。。并显示两个表达式在C++中是否真的等价,这是一个非常非常非常复杂的问题…< /P>
我设计的退化示例()(注意它不是很退化…它只是基于一个小的编程错误)是基于考虑good
abool
,创建两个类UnixDateTime
和SmallUnixDateTime
,使用newClusters()
返回SmallUnixDateTime
和newSeed()
返回UnixDateTime
。它们都应用于包含Unix日期时间,格式为从1970-01-01午夜开始的秒数SmallUnixDateTime
使用int
,而UnixDateTime
使用long
。两者都可以隐式转换为bool
(如果它们的内部值是!=0
,它们就会返回,这是“经典的”),但是UnixDateTime
甚至可以隐式转换为SmallUnixDateTime
(这是错误的,因为可能会丢失精度……这是一个小的编程错误)。转换失败时,返回设置为0
的SmallUnixDateTime
。在本例的代码中,始终存在一个转换:从SmallUnixDateTime
到bool
或从UnixDateTime
到bool
在这个类似但不同的例子中:
good = !m_seedsfilter ? true
: m_seedsfilter==1 ? newClusters(Sp)
: newSeed(Sp);
有两种可能的路径:SmallUnixDateTime
(newClusters(Sp)
)转换为bool
,或者UnixDateTime
(newSeed(Sp)
)首先转换为SmallUnixDateTime
,然后转换为bool
。很明显,这两个表达式并不相等
要使其工作(或“不工作”),
newSeed(Sp)
返回一个不能包含在SmallUnixTime
(std::numeric\u limits::max()+1LL
)中的值。如果按以下方式重写,则编写的语句可以得到改进
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)
可能应该注意的是,我上面的重写只要是操作符就可以了!()
对于m_seedsfilter
类型,不重写。如果是,那么您必须使用它来保留原始版本的行为
good = !m_seedsfilter ? true :
m_seedsfilter==1 ? newClusters(Sp) :
newSeed(Sp);
…正如xanatos下面的评论所证明的,如果您的newClusters()
和newSeed()
方法返回的类型不同,并且如果这些类型是使用精心编制的无意义转换运算符编写的,那么您将不得不恢复到原始代码本身(虽然希望格式更好,就像在xanatos自己的帖子中一样)以忠实地复制与原始帖子完全相同的行为。但是在现实世界中,没有人会这样做,所以我上面的第一个版本应该可以
更新,原始帖子/答案发布两年半后: 有趣的是,@TimothyShields和我不断获得这方面的支持票,Tim的答案似乎始终保持在这个答案的支持票的50%左右,或多或少(截至本次更新,43对22) 我想我应该添加另一个例子,说明三元语句在使用得当时可以增加的清晰度。下面的例子是我为callstack使用率分析器(一个分析已编译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)");
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)");
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)");
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)");
2.使用三元运算符,分别调用Console.Write():
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)");
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)");
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)");
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)");
3.使用三元运算符,折叠为对Console.Write()的单个调用:
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)");
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)");
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)");
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)");
有人可能会说,上面三个例子之间的区别很小,既然它很小,为什么不选择更简单的(第一个)变体呢?这都是为了简洁;用“尽可能少的话”表达一个想法这样,当我说到点子的结尾时,听者/读者仍能记住点子的开头。当我和小孩子说话时,我会用简单、简短的句子
good = !m_seedsfilter ? true :
( m_seedsfilter == 1 ? newClusters(SP) :
newSeed(SP) );
!m_seedsfilter ? good=true : m_seedsfilter==1 ? good=newClusters(Sp) : good=newSeed(Sp);
if (!m_seedsfilter)
{
good = true;
}
else
{
if (m_seedsfilter == 1)
{
good = newClusters(Sp);
}
else
{
good = new Seed(Sp);
}
}