如何在if语句中将否定与声明结合起来?

时间:2016-07-17 19:08:17

标签: c++

当使用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);
}

但据我所知,它并没有真正发挥作用。

有没有诀窍要做到这一点?

4 个答案:

答案 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);
}

这基本上就是你想要的。

它位于feature-complete draft

答案 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 ); 语法修改是令人厌恶的。