[解決済み】複数のstd::collectionをCSVに出力する関数 / 1行目の反復処理
2022-02-17 23:34:59
質問
次のようなシグネチャ(またはそれに類するもの)を持つ関数を書きたい。
template <typename... Ts>
void collection_to_csv(const std::string filepath, const Ts& ... containers);
この関数は、csv ファイルを以下の場所にあるファイルに書き込む必要があります。
filepath
コンテナはSTDの反復可能なコンテナで、出力されるCSVファイルのカラムを定義することができます。例えば、次のように使用することができる。
std::vector<int> column1{1, 2, 3, 4};
std::list<float> column2{1.5, 2.5, 3.5, 4.5};
collections_to_csv(someFilePath, c1, c2);
これは可能なのでしょうか?今までは、こんな感じでバリアド・テンプレートを使おうとしていました。
template <typename... Ts>
void collection_to_csv(const std::string filepath, std::initializer_list<std::string> headers, const Ts& ... containers)
{
std::ofstream file;
file.open(filepath, std::ofstream::out | std::ofstream::trunc);
for (std::size_t irow=0; irow < size; ++irow)
{
for (const auto& container : containers) //But how to iterate through the variadic arguments when they could be different types?
{
file << container[i] << ",";
}
}
file.flush();
file.close();
}
私が見た限りでは、バリアディックテンプレートは再帰を使って「反復」されるようですが、これでは「列が先」の反復順序を強いられることになります。私は「行が最初」の順序が必要で、バリアディックテンプレートはここでは間違ったツールかもしれないと思わせています。より良いアプローチはありますか?
どのように解決するのですか?
を使用することができます。
std::tuple
のイテレータを格納するために、それぞれの
containers
を使用し、その後に
std::apply
というように、1つずつインクリメントしていきます。
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include <list>
template <typename... Ts>
void collection_to_csv(const Ts&... containers) {
const auto ncol = [](const auto& first, const auto&...) {
return first.size();
}(containers...);
auto iters = std::make_tuple(containers.begin()...);
for (std::size_t icol = 0; icol < ncol; ++icol) {
std::apply(
[&](auto&... iter) {
((std::cout << *iter++ << ","), ...);
}, iters);
std::cout << "\n";
}
}
int main() {
std::vector column1{1, 2, 3, 4};
std::list column2{1.5, 2.5, 3.5, 4.5};
collection_to_csv(column1, column2);
}
C++23の導入に感謝
views::zip
,
collection_to_csv
を使うだけで、よりシンプルに実装できます。
views::zip
つまり、すべての
containers
を作成し、その要素を1つずつ繰り返し処理します。
#include <ranges>
#include <tuple>
template <typename... Ts>
void collection_to_csv(const Ts&... containers) {
for (const auto& values : std::ranges::zip_view(containers...)) {
std::apply(
[](const auto&... value) { ((std::cout << value << ","), ...); }, values);
std::cout << "\n";
}
}
関連
-
[解決済み】C++でint型に無限大を設定する
-
[解決済み] [Solved] Error C1083: Cannot open include file: 'stdafx.h'
-
[解決済み] error: 'ostream' does not name a type.
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み】エラー。switchステートメントでcaseラベルにジャンプする
-
[解決済み】クラステンプレートの使用にはテンプレート引数リストが必要です
-
[解決済み】標準ライブラリにstd::endlに相当するタブはあるか?
-
[解決済み】 while(cin) と while(cin >> num) の違いは何ですか?)
-
[解決済み】変数やフィールドがvoid宣言されている
-
[解決済み】'std::cout'への未定義の参照
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】構造体のベクター初期化について
-
[解決済み】coutはstdのメンバではない
-
[解決済み】コンストラクターでのエラー:識別子を期待されますか?
-
[解決済み】C++のGetlineの問題(オーバーロードされた関数 "getline "のインスタンスがない
-
[解決済み】C++ 式はポインタからオブジェクトへの型を持っている必要があります。
-
[解決済み】文字列関数で'char const*'のインスタンスを投げた後に呼び出されるterminate [閉店].
-
[解決済み】C++プログラムでのコンソールの一時停止
-
[解決済み】指定範囲内の乱数で配列を埋める(C++)
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】デバッグアサーションに失敗しました