1. ホーム
  2. c++

[解決済み] forループの中でif文を使わないようにするには?

2022-08-19 07:38:25

質問

というクラスがあります。 Writer というクラスがあり、このクラスには関数 writeVector のように

void Drawer::writeVector(vector<T> vec, bool index=true)
{
    for (unsigned int i = 0; i < vec.size(); i++) {
        if (index) {
            cout << i << "\t";
        }
        cout << vec[i] << "\n";
    }
}

パフォーマンスを気にしつつも、重複したコードを持たないようにしています。 関数の中で、私は if (index) のラウンドごとにチェックをしています。 for -ループの各ラウンドで、たとえ結果が常に同じであっても、をチェックします。 これは、パフォーマンスについて心配することに反しています。

の外側にチェックを置くことで、簡単にこれを回避することができました。 for -ループの外側に配置することで簡単に回避できます。 しかし、重複するコードのロードを取得します。

void Drawer::writeVector(...)
{
    if (index) {
        for (...) {
            cout << i << "\t" << vec[i] << "\n";
        }
    }
    else {
        for (...) {
            cout << vec[i] << "\n";
        }
    }
}

つまり、これらは両方とも私にとって悪い解決策なのです。 私が考えているのは、2つのプライベート関数で、1つはインデックスを出力して、もう1つを呼び出すことです。 もう一方は値のみを出力します。 しかし、私のプログラムでは、それをどのように使うのかがわかりません。 if をチェックし、どちらを呼び出すかを確認する必要があります...

問題によると、ポリモーフィズムは正しい解決策のように思えます。 しかし、私はここでそれをどのように使用すべきかを見ることができません。 この種の問題を解決するために望ましい方法は何でしょうか?

これは本当のプログラムではありません。 この種の問題をどのように解決するのが望ましいかを知りたいだけです。

どのように解決するのですか?

ループの本体をファンクタとして渡す。 コンパイル時にインライン化され、性能上のペナルティはありません。

変化するものを渡すという考え方は、C++標準ライブラリに普遍的に存在するものです。これは 戦略パターンと呼ばれています。

C++11を使うことが許されるなら、こんなこともできる。

#include <iostream>
#include <set>
#include <vector>

template <typename Container, typename Functor, typename Index = std::size_t>
void for_each_indexed(const Container& c, Functor f, Index index = 0) {

    for (const auto& e : c)
        f(index++, e);
}

int main() {

    using namespace std;

    set<char> s{'b', 'a', 'c'};

    // indices starting at 1 instead of 0
    for_each_indexed(s, [](size_t i, char e) { cout<<i<<'\t'<<e<<'\n'; }, 1u);

    cout << "-----" << endl;

    vector<int> v{77, 88, 99};

    // without index
    for_each_indexed(v, [](size_t , int e) { cout<<e<<'\n'; });
}

このコードは完璧ではありませんが、アイデアを得ることができます。

古いC++98では、このようになります。

#include <iostream>
#include <vector>
using namespace std;

struct with_index {
  void operator()(ostream& out, vector<int>::size_type i, int e) {
    out << i << '\t' << e << '\n';
  }
};

struct without_index {
  void operator()(ostream& out, vector<int>::size_type i, int e) {
    out << e << '\n';
  }
};


template <typename Func>
void writeVector(const vector<int>& v, Func f) {
  for (vector<int>::size_type i=0; i<v.size(); ++i) {
    f(cout, i, v[i]);
  }
}

int main() {

  vector<int> v;
  v.push_back(77);
  v.push_back(88);
  v.push_back(99);

  writeVector(v, with_index());

  cout << "-----" << endl;

  writeVector(v, without_index());

  return 0;
}

繰り返しになりますが、このコードは完璧ではありませんが、アイデアを与えてくれます。