当使用C风格的返回代码来指示错误时,看到这样的代码非常常见:
if (do_something()) {
do_something_else();
} else {
report_failure();
}
有时,如果一个块比另一个块大得多,您可能需要重新排序"处理失败"阻止" do_something_else"块。
if (!do_something()) {
report_failure();
} else {
do_something_else();
}
(或者,当它真的是C代码时,代码可能是0
表示成功而不是失败,但让我们忽略它。)
当我使用像boost::optional
这样的C ++惯用语或建议的std::expected
类型之一时,通常我想要做的是在if语句的条件中放置一个声明:
if (auto ok = do_something()) {
do_something_else(*ok);
} else {
report_failure(ok.error());
}
我喜欢这样做,因为这样,ok
严格包含在范围内,在两个街区外不可见。
然而,一旦我这样做,如果我愿意的话,我就不能对这两个分支进行重新排序,这可能会让我感到非常恼火,但仍然如此。
我真正想要的是语法
if not (auto ok = do_something()) {
report_failure(ok.error());
} else {
do_something_else(*ok);
}
但据我所知,它并没有真正发挥作用。
有没有诀窍要做到这一点?
答案 0 :(得分:2)
您可以添加额外的范围:
{
auto ok = do_something();
if (! ok) {
report_failure(ok.error());
} else {
do_something_else(*ok);
}
}
我个人不会添加这些大括号,因为范围应该从代码的其余部分清楚,如果你在一个函数中有太多的功能,你应该重构代码......
答案 1 :(得分:2)
C++17将引入此语法:
if (auto ok = do_something(); !ok) {
report_failure(ok.error());
} else {
do_something_else(*ok);
}
这基本上就是你想要的。
答案 2 :(得分:0)
嗯,脑子里有很多肮脏的伎俩,但是,假设你不想去那里,这里有一个非宏的伎俩:
template <class T> class notter {
T d_t;
public:
notter(T &t) : d_t(t) {}
notter(T t) : d_t(t) {}
operator bool() { return !d_t; }
T &data() { return d_t; }
};
现在您可以将其用作:
if (notter<int> a = do_something()) {
report_failure();
}
else {
do_something_else(a.data());
}
这假定do_something
返回int
。您可以避免使用decltype
命名类型:
if (notter<decltype(do_something())> a = do_something()) {
但在这种情况下,这可能有点过分。
你可以根据自己的需要调整它,如果data()
对你来说过于冗长,或者你只想要其中一个构造函数,或者进行更多的替换&#34; ;对于optional<>
(根据Duthomhas的评论)或expected<>
- 您可以使用模板专精。
此外,您可以从std::make_shared()
提示并提示:
template<class T> notter<T> make_notter(T t) { return notter<T>(t); }
并使用它:
if (auto a = make_notter(do_something())) {
答案 3 :(得分:0)
好吧,所以这里有一个小小的课程可以做你想要的。装扮你喜欢。
string[] scopes = new string[] {
PlusService.Scope.PlusLogin,
PlusService.Scope.UserinfoEmail,
PlusService.Scope.UserinfoProfile
};
var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "xxx.apps.googleusercontent.com",
ClientSecret = "xxxx"
},
Scopes = scopes,
DataStore = new FileDataStore("Store")
});
var token = new TokenResponse {
AccessToken = "[your_access_token_here]",
RefreshToken = "[your_refresh_token_here]"
};
var credential = new UserCredential(flow, Environment.UserName, token);
按照您的预期使用它:
template <typename T>
struct not_optional_type: public optional <T>
{
typedef optional <T> base_type;
not_optional_type( const base_type& v ): base_type( v ) { }
operator bool () const { return !(base_type)(*this); }
T operator * () const { return *(base_type)(*this); }
};
template <typename T>
not_optional_type <T>
not_optional( const optional <T> && v )
{
return not_optional_type <T> ( v );
}
我个人认为提议的if (auto ok = not_optional( do_something() ))
fooey();
else
success( *ok );
语法修改是令人厌恶的。