ねらい
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;
}
参考