2017-12-21 11 views
0

私はこのように、クラスのメンバ変数に値を代入するC++ 17の構造バインディングを使用したい:構造化バインディングを使用してクラスメンバーを割り当てることはできますか?

#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(); 
} 

しかし、このコードは、(打ち鳴らす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. 

ラムダキャプチャには多少の混乱があるようです。確かにこれは動作します:

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

しかし、新しいローカル変数を使用する必要はありません。これは構造化バインディングで可能ですか?

+0

別の変数ではなく、 'Calculator'に' Result'オブジェクトを置くことができると思います。 – Galik

+0

@Galikはい、これは疑問を実証するための少し複雑な例でした。 :) –

答えて

5

使用std::tie既存のオブジェクトに値を割り当てるには:

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

それはC++ 11に追加された理由です。もちろん、Resultを使用してstd::tupleを使用する必要はありません。どのようなIMOがそのような特別な「複数のものを返す」シナリオに適しているか。

構造化バインディングは、の新しいオブジェクトを排他的に宣言しています。

C++ 1zがテーブルに載っているので、さらに優れた別のアプローチは、ホイールを再発明しないことです。これは、「値、またはいないがあるかもしれない」の明確な意味を持っているstd::optional

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

を返します。ところで


、無条件に負入力とstd::sqrtを呼び出すことは悪い考えです。特に以前に特別な方法で浮動小数点環境を設定していない場合は、

+0

私は個人的に 'std :: tuple'のファンではありません。' std:tie'はあまりにも悪くはありませんが、 '<0>'または 'get <1>' 。私は 'std :: optional'が両方よりも優れていると思います - それを試してみましょう。ありがとう! –

+1

@JoshPeterson - 私は 'std :: tuple'についてあなたの意見を得ています。通常、 'enum {value、error}'を追加することで軽減します。したがって、コールは 'std :: get (...)'のようになります – StoryTeller

関連する問題