提问人:Zebrafish 提问时间:9/1/2017 最后编辑:BoannZebrafish 更新时间:12/29/2017 访问量:7714
我可以在一行上写这个带有变量声明的 if 语句吗?[复制]
Can I write this if statement with a variable declaration on one line? [duplicate]
问:
我想知道有没有办法把它放在一行上?
if (auto r = getGlobalObjectByName(word)) r->doSomething; // This works fine
if (!auto r = getGlobalObjectByName(word)) r->doSomething; // Says "expected an expression"
if (auto r = getGlobalObjectByName(word) == false) r->doSomething; // Also doesn't work.
我还尝试用额外的括号将其包围,但这似乎不起作用。我发现这在一行上做起来真的很方便。
答:
52赞
Passer By
9/1/2017
#1
从 C++ 17 开始,您可以使用初始值设定项 if 语句:
if (auto r = getGlobalObjectByName(word); !r) r->doSomething;
语义如下:
if (init-statement; condition) statement
与“传统”if 语句的唯一区别是 ,它初始化块作用域中的变量,类似于 for 循环。init-statement
评论
2赞
Zebrafish
9/1/2017
我一直在诅咒语言添加更多功能,但有些东西我挖掘了。谢谢
1赞
Passer By
9/1/2017
@Zindarod 分号后面的表达式的行为与以前一样。
2赞
Bathsheba
9/1/2017
它可能是带有重载运算符的非指针类型。->
1赞
Bathsheba
9/1/2017
但假设其他情况也是不必要的。
1赞
Shamtam
9/1/2017
有什么理由不行吗?if (auto r = !getGlobalObjectByName(word)) r->doSomething;
4赞
Galik
9/1/2017
#2
你要做的很好。通过在 if 中定义变量,请限制其作用域。这有助于在杂散变量达到其目的后减少它们的数量。
使用这种技术,如果你想遵循否定路径,你需要使用其他的,如下所示:
if(auto r = getGlobalObjectByName(word))
{
r->doSomething();
}
else
{
// r == nullptr
// so do something else
}
13赞
Martin Bonner supports Monica
9/1/2017
#3
如果您有 C++17,请使用表单。如果没有,您有三个选择:if (init statement; condition)
不要再试图把这一切放在一行上。例如:
auto r = getGlobalObjectByName(word); if (!r) r->doSomething();
使用:
else
if (auto r = getGlobalObjectByName(word)) {} else r->doSomething();
(请注意,这需要一个智能指针,该函数具有非常奇怪的语义。OTOH,我认为这实际上是一小段示例代码,而不是您的实际代码)。r
operator bool()
我想我只会在将所有内容都放在一行非常重要的情况下使用表单(例如,保留代码的表格格式)。else
评论
0赞
Ruslan
9/1/2017
r
可能不是智能指针,例如类,它转换为指示失败,并且可以例如在这种情况下提供错误消息。Status
false
0赞
Martin Bonner supports Monica
9/1/2017
@Ruslan 是的,它可以,但是对我来说,提供错误消息的重载似乎是操作员重载滥用。 会更干净。operator ->
r.Error().doSomething()
0赞
Ruslan
9/1/2017
嗯,是的,确实,没有想到.operator->
4赞
Erroneous
9/2/2017
#4
还有一种方法可以用 lambda 和 C++14 做到这一点,但它看起来确实很愚蠢。
[](auto r){ if(!r)r->doSomething(); }(getGlobalObjectByName(word));
在 C++11 中,你也可以做这个可怕的混乱(同样的想法,只是没有auto
)
[](decltype(getGlobalObjectByName(word)) r){ if(!r)r->doSomething(); }(getGlobalObjectByName(word));
它肯定不比Martin Bonner提到的这个更清晰的C++11版本更好:
{
auto r = getGlobalObjectByName(word);
if(!r)r->doSomething();
}
在这里,您的代码很清楚,您只想在 if 语句的持续时间内存在。r
评论
0赞
Zebrafish
12/29/2017
我不明白你写的第一行发生了什么。您声明一个 lambda,然后立即在一行上调用该函数,就好像函数的返回值作为参数传递给 lambda 一样。这是 C++14 的功能吗?它叫什么?
0赞
Erroneous
12/29/2017
@Zebrafish C++14 功能是 lambda 的自动参数。该代码只是构造一个 lambda 并立即调用其 operator()。如果我使用类型而不是自动,我可以在 C++11 中完成。
2赞
Ruslan
9/2/2017
#5
在 C++ 17 之前,您可以定义一个包装类,如下所示:
#include <utility>
template<typename T>
class NotT
{
T t;
public:
template<typename U>
NotT(U&& u) : t(std::move(u)) {}
explicit operator bool() const { return !t; }
T & value() { return t; }
T const& value() const { return t; }
};
template<typename T> NotT<T> Not(T&& t)
{
return NotT<T>(std::move(t));
}
#include <memory>
#include <iostream>
int main()
{
if(auto p=Not(std::make_shared<int>(2134)))
std::cout << "!p: p=" << p.value().get() << '\n';
else
std::cout << "!!p: p=" << p.value().get() << ", *p=" << *p.value() << '\n';
}
评论
r
false
r->doSomething
r
operator!()
bool
operator->()
false
)if
auto r = getGlobalObjectByName(word) == false
意味 着auto r = (getGlobalObjectByName(word) == false)