LoginSignup
0
0

More than 1 year has passed since last update.

可変引数テンプレートを用いたバイナリデータの読み書き

Last updated at Posted at 2022-07-25

ねらい

C++でバイナリデータの書きこみをする際に、変数を定義しなくとも良いようにしたい。 画像ファイルとかのヘッダ部分とかを描く際に短くしたいというのが動機です。
例えば、こんな感じ(個数は任意)。

file_write(fout, int(10), double(20.123), float(30.4f)); 

実装

可変引数テンプレートを使ったらうまく行きそうでしたので、実装してみました(要C++11)。
https://cpprefjp.github.io/lang/cpp11/variadic_templates.html

test.cpp
#include <fstream>
#include <iostream>
#include <array>
#include <vector>
void file_write( std::ofstream& fout) {}
template <class Head, class... Tail>
void file_write(std::ofstream& fout, Head&& head, Tail&&... tail){
        fout.write(reinterpret_cast<char*>(&head), sizeof(Head));
        file_write(fout, std::forward<Tail>(tail)...);
}
void file_read( std::ifstream& fin) {}
template <class Head, class... Tail>
void file_read(std::ifstream& fin, Head&& head, Tail&&... tail){
        fin.read(reinterpret_cast<char*>(&head), sizeof(Head));
        file_read(fin, std::forward<Tail>(tail)...);
}
int main(){
        std::ofstream fout("input.bin", std::ios::binary);
        file_write(fout, int(10), double(20.123), float(30.4f));
        file_write(fout, int(10), int(20), int(30));
        fout.close();

        std::ifstream fin("input.bin", std::ios::binary);
        int a;
        double b;
        float c;
        std::array<int, 3> ar{};
        file_read(fin, a, b, c, ar);
        fin.close();
        std::cerr<<a<<" "<<b<<" "<<c<<" "<<ar[0]<<" "<<ar[1]<<" "<<ar[2]<<std::endl;
        return 0;
}

この実装ですと、

  • 明示的にキャストが必要。
  • 配列とかは無理そう ofstream::write()で直接書き込める必要がある。std::arrayだったら配列でもできる(vectorは×っぽい)。

あたりの制約があります。

追記

元々は、file_readをstd::tupleの返り値でとるようにしたいとおもっていました。つまり,

auto [a,b,c] = file_read<int, double, float>(fin); 

以下の通り、std::apply()とパラメータパックの展開をうまく使えばできるということがわかりました(C++17構造化束縛(auto[a, b, c])はC++17)。

template<typename... Args>
std::tuple<Args...> file_read(std::istream& in) {
        std::tuple<Args...> result;
        std::apply ([&in](Args &... v){(in.read( reinterpret_cast<char*>(&v), sizeof(v)), ...);}, result );
        return result;
}

参考

0
0
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
0
0