也许是因为Perl的影响,我喜欢使用以下语法
condition && do_something();
而不是
if ( condition )
{
do_something();
}
(我知道我可以将后者排成一行而没有括号,但这不是重点。)
我做了几次测试(下面),这是有效的。 但我在标准中找不到参考,说它是合法的。 可以隐含在
中但我不完全确定(我检查了C ++ 98,很抱歉老式,但即使是C标准就足够了)。
注意:我确实意识到为了工作,最后一个表达式(do_something)也必须可以转换为bool,这对于选择语句来说不是必需的。这当然是一个严重的限制。
所以问题是:
道歉如果证明是重复的,我找不到任何东西,但可能是因为我没有使用正确的关键词。
#include <cassert>
bool sayYes()
{
return true;
}
bool sayNo()
{
return false;
}
int main( int args, char* argv[] )
{
bool a = true;
bool b = false;
int i = 0;
a && ( i = 1 );
assert( i == 1 );
!a && ( i = 0 );
assert( i == 1 );
( a || b ) && ( i = 0 );
assert( i == 0 );
sayYes() && ( i = 1 );
assert( i == 1 );
( sayNo() || sayYes() ) && ( i = 0 );
assert( i == 0 );
return 0;
}
答案 0 :(得分:4)
这完全合法。来自[expr.log.and]:
&&
保证从左到右 评估:如果第一个操作数为false
,则不评估第二个操作数。
expr() && fun()
相当于if (expr()) fun()
(假设fun()
返回可转换为bool
的内容)。在编写复合条件表达式时,这是一个非常重要的属性。例如,只有在我们知道指针有效后才解除引用指针:
if (ptr && ptr->foo()) { ... }
那就是说,如果你真正想要的是:
if (expr()) {
fun();
}
写下来。编译器将以任何一种方式生成相同的代码,但您尝试执行的操作的目的将更加清晰。
答案 1 :(得分:3)
是的,这是合法的。后跟;
的表达式是有效的陈述。
有些人可能会觉得它很混乱。
如果有副作用,则无法优化。
请注意,虽然在C ++中&&
可能重载。如果它超载,则丢弃操作员的短切属性。 那会造成奇怪的效果。主要是因为这个原因,我会反对这种风格。
答案 2 :(得分:3)
我认为我有义务指出这一点。 你应该不惜一切代价避免你想要做的事情。你试图操纵语言本身的语法太模仿另一个人的语法。而且你这样做是因为你对使用 if语句的另一种语法感到更舒服。你不能这样想,有一次这个代码会被其他人看到,当他们看到这种奇怪的语法时,他们会完全混淆。如果我在任何c ++库中看到我将要使用的东西,我就不会使用它而再也不用担心它了。
也许你决定用camel case命名所有变量,或者你认为你应该在private
,protected
或public
说明符之前省略填充的空格,或者也许你只是想把所有的括号放在一个新的行上。那时你应该说:
...我喜欢使用以下内容......
但是当你决定不喜欢语言如何读取if-statement
或函数声明时,你必须处理它。为什么?因为它是如何完成的,那就是语言的编写方式。您尝试做的事情相当于更改英文字母的字母,因为您对“英语字母表”的使用方式更加满意。看你的母语。
每当我看到&&
时,我认为有三件事之一,r-value
,universal ref
和AND
。我是否想到if
?没有。我为什么要说我以前用Perl编程,嘿,你怎么知道我是否熟悉这样的语法?
所以基本上......
你用c ++写作,你不是用Perl写的。 在某些地方,您将不得不用不同的语言编写,那么您是否会尝试操纵它的语法?你甚至可以做这样的事情,它从哪里开始,它停在哪里?
答案 3 :(得分:1)
我必须承认我使用这种技术,因为它经常看起来更简洁(至少对我和我的同事来说)与其他操作符表示相结合。
考虑这个(人为的但是指示性的)例子:
#include <string>
#include <stdexcept>
#include <exception>
#include <regex>
struct invalid_number : std::logic_error
{
using std::logic_error::logic_error;
};
template<class Excep, class...Args>
[[noreturn]]
bool raise(Args&&...args)
{
throw Excep(std::forward<Args>(args)...);
}
int parse_number(const std::string& s)
try
{
const std::regex re("^\\d+$");
std::regex_match(s, re) or raise<std::invalid_argument>(s);
return std::stoi(s);
}
catch(...)
{
std::throw_with_nested(std::invalid_argument(__func__));
}