Is it possible to use structured bindings to assign class members?

我的未来我决定 提交于 2019-12-20 05:26:14

问题


I'd like to use C++ 17 structured bindings to assign a value to a class member variable, like this:

#include <cmath>
#include <iostream>

struct Result {
  double value;
  bool error;
};

Result square_root(double input) { return {std::sqrt(input), input < 0}; }

struct Calculator {
  double result_;
  bool error_;

 public:
  void ComputeSquareRoot(double input) {
    [ result_, error_ ] = square_root(input);
  }

  void DisplayResult() {
    if (error_)
      std::cout << "Cannot take the square root of a negative number.\n";
    else
      std::cout << "The square root is " << result_ << ".\n";
  }
};

int main(int argc, char* argv[]) {
  Calculator calc;
  calc.ComputeSquareRoot(64);
  calc.DisplayResult();
}

But this code fails to compile with the following error (using clang 5.0):

> clang++ structured_bindings.cpp -std=c++17 -o structured_bindings
structured_bindings.cpp:20:7: error: 'result_' in capture list does not name a variable
    [ result_, error_ ] = square_root(input);
      ^
structured_bindings.cpp:20:16: error: 'error_' in capture list does not name a variable
    [ result_, error_ ] = square_root(input);
               ^
structured_bindings.cpp:20:25: error: expected body of lambda expression
    [ result_, error_ ] = square_root(input);
                        ^
3 errors generated.

There seems to be some confusion with lambda capture. Certainly this will work:

auto[result, error] = square_root(input);
result_ = result;
error_ = error;

But I would like to avoid the need to use new local variables. Is this possible with structured bindings?


回答1:


Use std::tie to assign values to existing objects:

std::tie(result_, error_) = square_root(input);

That's why it was added to C++11. Of course, you'd need to forego using Result in favor of a std::tuple. Which IMO is better for such ad-hoc "return multiple things" scenarios.

Structured bindings are exclusively for declaring new names.

Another approach, which could be even better, since C++1z is on the table, is to not re-invent the wheel. Return a std::optional

auto square_root(double input) {
   return input < 0 ? std::nullopt : std::optional{std::sqrt(input)}; 
}

This has the clear semantics of "there may be a value, or not".


By the way, unconditionally calling std::sqrt with a negative input is a bad idea. Especially if you don't configure your floating point environment in any special way prior.



来源:https://stackoverflow.com/questions/47924527/is-it-possible-to-use-structured-bindings-to-assign-class-members

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!