テキストアーカイブを使用する場合、ブーストシリアル化ライブラリはdoubleの特別な値を正しく処理できません。つまり、NaN、+ inf、または-infを逆シリアル化しようとすると、エラーが発生します(たとえば、このトピックを参照)。
したがって、これらの値を処理するために、make_arrayまたはmake_binary_object(ブーストドキュメントを参照)に似たラッパークラス/メソッドを記述したいと思います。私はそれをこのように使いたい:
class MyClass {
public:
double value;
template <class Archive>
void serialize(Archive &ar, const unsigned int){
ar & Double_wrapper(value);
}
};
ただし、ラッパークラスが内部でどのように機能するかを理解できません。特に、逆シリアル化するときに、元の変数(この場合は値)への接続をどのように維持するのかがわかりません。
私は次のようなラッパーを書こうとしました:
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/wrapper.hpp>
#include <boost/serialization/tracking.hpp>
#include <limits>
#include <cmath>
class Double_wrapper {
private:
enum double_type {DT_NONE, DT_NAN, DT_INF, DT_NINF};
double& value;
public:
Double_wrapper(double& val):value(val){}
Double_wrapper(Double_wrapper const& rhs):value(rhs.value) {}
private:
friend class boost::serialization::access;
template<class Archive>
void save(Archive & ar, const unsigned int) const {
double_type flag = DT_NONE;
double val = value;
if (!std::isfinite(val)) {
if (std::isnan(val)) {
flag = DT_NAN;
} else if (val > 0) {
flag = DT_INF;
} else {
flag = DT_NINF;
}
val = 0;
}
ar & val;
ar & flag;
}
template<class Archive>
void load(Archive & ar, const unsigned int) const {
double_type flag;
ar & value;
ar & flag;
switch (flag) {
case DT_NONE: break;
case DT_NAN: value = std::numeric_limits<double>::quiet_NaN(); break;
case DT_INF: value = std::numeric_limits<double>::infinity(); break;
case DT_NINF: value = -std::numeric_limits<double>::infinity();
}
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
};
BOOST_CLASS_IS_WRAPPER(Double_wrapper)
BOOST_CLASS_TRACKING(Double_wrapper, boost::serialization::track_never)
ただし、これは、ラッパーがどのように機能するかを理解するというよりも、試行錯誤の結果です。私が結論付けたドキュメントのこの部分から、クラスをラッパーとして宣言する必要があると結論付けました。しかし、それは機能していないようです。
このMWEで上記のコードを使おうとすると
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/wrapper.hpp>
#include <boost/serialization/tracking.hpp>
#include <limits>
#include <cmath>
#include <boost/archive/tmpdir.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <fstream>
#include <iostream>
class Double_wrapper {
private:
enum double_type {DT_NONE, DT_NAN, DT_INF, DT_NINF};
double& value;
public:
Double_wrapper(double& val):value(val){}
Double_wrapper(Double_wrapper const& rhs):value(rhs.value) {}
private:
friend class boost::serialization::access;
template<class Archive>
void save(Archive & ar, const unsigned int) const {
double_type flag = DT_NONE;
double val = value;
if (!std::isfinite(val)) {
if (std::isnan(val)) {
flag = DT_NAN;
} else if (val > 0) {
flag = DT_INF;
} else {
flag = DT_NINF;
}
val = 0;
}
ar & val;
ar & flag;
}
template<class Archive>
void load(Archive & ar, const unsigned int) const {
double_type flag;
ar & value;
ar & flag;
switch (flag) {
case DT_NONE: break;
case DT_NAN: value = std::numeric_limits<double>::quiet_NaN(); break;
case DT_INF: value = std::numeric_limits<double>::infinity(); break;
case DT_NINF: value = -std::numeric_limits<double>::infinity();
}
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
};
BOOST_CLASS_IS_WRAPPER(Double_wrapper)
BOOST_CLASS_TRACKING(Double_wrapper, boost::serialization::track_never)
///////////////////////////////////////////////////////////////////////////////////////
class MyClass {
public:
double value;
template <class Archive>
void serialize(Archive &ar, const unsigned int){
ar & Double_wrapper(value);
}
};
///////////////////////////////////////////////////////////////////////////////////////
int main() {
MyClass tmp;
tmp.value = std::numeric_limits<double>::quiet_NaN();
std::cout << "value=" << tmp.value << std::endl;
std::string filename(boost::archive::tmpdir());
filename += "/tmp.txt";
//Output
std::ofstream ofs(filename.c_str(), std::ios_base::out);
boost::archive::text_oarchive oar(ofs);
oar << tmp;
ofs.close();
//Input
MyClass newtmp;
std::ifstream ifs(filename.c_str(), std::ios_base::in);
boost::archive::text_iarchive iar(ifs);
iar >> newtmp;
std::cout << "value=" << newtmp.value << std::endl;
}
失敗します。それは私にエラーを与えます
エラー:タイプ「Double_wrapper」の右辺値からのタイプ「Double_wrapper&」の非定数参照の無効な初期化
ラインのために
ar&Double_wrapper(value);
だから私は何をすべきかわからない。参照の使用は機能しないようです。ポインタはトリックを行いますか?これはまったく機能しますか?
どんな助けや説明も大歓迎です!
Ubuntuでブーストバージョン1.58を使用しています。
更新コメントに記載されているように、コードはvc ++で動作するようです。ただし、このスレッドで行われたステートメントを解釈することは、実際にはそうではないことを示唆しているようです。
それにもかかわらず、MSVCがそれを受け入れた理由は、MSVCが、非定数参照にバインドされたときに一時的なものの存続期間を延長する(邪悪な)非標準の拡張機能を持っているためである可能性があります。
これを正しく理解していれば、保存して新しいインスタンスで逆シリアル化しようとした後にプログラムをシャットダウンしても、機能しなくなるはずです。
更新JohnZwinckが提案したように、通話を置き換えることで回避策がある可能性があります
ar & Double_wrapper(value);
沿って
Double_wrapper wrapper(value);
ar & wrapper;
ただし、これは、ブーストシリアル化のラッパーオブジェクトの意図された動作ではないようです。さらに、このソリューションが安定しているかどうかは(私には)不明です(すべてのc ++コンパイラで実行する必要があります)。
g ++ 5.4.0およびclang ++ 3.8.0を搭載したコンピューターで動作するようです。さらに、Rextester(ブースト1.6)のvc ++で動作します。
rextester(ブースト1.54)でg ++ 4.9.3を使用して実行すると、アーカイブ例外が生成されます。(おそらく無関係の)リンカーエラーのため、rextesterのclang3.7またはcoliruのg ++ 6.1.0ではまだテストできませんでした。
私はこれの代わりに思う:
ar & Double_wrapper(value);
これを行う必要があります:
Double_wrapper wrapper(value);
ar & wrapper;
エラーメッセージが、左辺値が必要な場所で右辺値を使用しているという事実について不平を言っている理由。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加