LoginSignup
21
22

More than 5 years have passed since last update.

std::tupleを使って複数の値を返す

Last updated at Posted at 2014-01-01

忘れる前にメモ.

設定

  • 関数の返り値として複数の値を返したい.
  • 例えば,何かの処理を行い,これに成功したら返って来た値を使用して処理,失敗したら何もしない,ということができるような簡単なコードを書きたい.
  • 返り値を受ける代わりにポインタを渡すのは関数インターフェースの見栄えがよろしくない.
  • 適当にエンコーディングを考えて,一つの返り値に複数の値の意味を埋め込んでしまうのは,もっとよろしくない.
  • 値が有効か,無効かを示すだけならBoost.Optionalがあるけど,標準ライブラリだけでどうにかしたい.
  • std::optionalが標準に入るのはまだ先のようだ…
  • C++11の範囲だけでどうにかする.

サンプルコード

とりあえず,サンプルを書きましたが,この例だとイテレータ使え,と言われそうですね.とりあえずパっと思い付いたものがこれなので,もっと良いサンプルがあればそれに書き直します.

返り値をstd::tupleにする場合のポイントとして,std::tieで返り値を受ける変数を指定する場合はconst宣言できない.
constな変数に返り値を代入したい場合は,普通にconst std::tuple<...>型の変数で受けて,std::getで値を参照することになる.ちょっと打つのが面倒かも.

有効か無効かを表わしたい場合,std::optionalが使えるようになったら,それを使った方が良さそう.あるいはおとなしくBoost.Optionalを使う.

#include <tuple>

#include <iostream>
#include <vector>

namespace before {

long find(const std::vector<int>& vec, const int a)
{
    for(size_t i = 0; i < vec.size(); i++) {
        if (vec[i] == a) {
            return i;
        }
    }
    return -1;
}

void demo()
{
    const std::vector<int> vec = {0, -1, 1, 2, -2, 3};

    const int a = 2;
    const long b = find(vec, a);
    if (b < 0) {
        std::cout << a << " is not contained in vec." << std::endl;
    } else {
        std::cout << a << " is contained at " << b << " in vec." << std::endl;
    }

    const int c = -5;
    const long d = find(vec, c);
    if (d < 0) {
        std::cout << c << " is not contained in vec." << std::endl;
    } else {
        std::cout << c << " is contained at " << d << " in vec." << std::endl;
    }
}

}

namespace after {

std::tuple<size_t, bool> find(const std::vector<int>& vec, const int a)
{
    for(size_t i = 0; i < vec.size(); i++) {
        if (vec[i] == a) {
            return std::forward_as_tuple(i, true);
        }
    }
    return std::forward_as_tuple(0, false);
}

void demo()
{
    const std::vector<int> vec = {0, -1, 1, 2, -2, 3};

    const int a = 2;
    size_t b;
    bool c;
    std::tie(b, c) = find(vec, a);
    if (c) {
        std::cout << a << " is contained at " << b << " in vec." << std::endl;
    } else {
        std::cout << a << " is not contained in vec." << std::endl;
    }

    const int d = -5;
    size_t e;
    bool f;
    std::tie(e, f) = find(vec, d);
    if (f) {
        std::cout << d << " is contained at " << e << " in vec." << std::endl;
    } else {
        std::cout << d << " is not contained in vec." << std::endl;
    }
}

template<class T, class V, class Option>
void puts_result(const T& value, const std::tuple<V, Option>& result) {
    if (std::get<1>(result)) {
        std::cout << value << " is contained at " << std::get<0>(result) << "." << std::endl;
    } else {
        std::cout << value << " is not contained." << std::endl;
    }
}

void demo2()
{
    const std::vector<int> vec = {0, -1, 1, 2, -2, 3};

    const int a = 2;
    const std::tuple<size_t, bool> b = find(vec, a);
    puts_result(a, b);

    const int c = -5;
    const std::tuple<size_t, bool> d = find(vec, c);
    puts_result(c, d);
}

}

int main()
{
    before::demo();
    after::demo();
    after::demo2();
}

参考文献

21
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
22