How to serialize boost::rational - serialization

I cannot serialize boost::rational<int>. I searched for a boost/serialize/rational.h header but it does not exist.
/usr/include/boost/serialization/access.hpp:118:9: error: ‘class boost::rational<int>’ has no member named ‘serialize’
Is there a way to achieve it?

Just serialize the numerator and denominator.
Here's the legwork, in semi-generic form (supports archives with named nodes, like XML serialization, too): Live On Coliru
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/rational.hpp>
#include <iostream>
namespace boost { namespace serialization {
template <typename Archive, typename T>
void save(Archive& ar, ::boost::rational<T> const& r, unsigned /*version*/)
{
int n = r.numerator(), d = r.denominator();
ar & boost::serialization::make_nvp("numerator", n);
ar & boost::serialization::make_nvp("denominator", d);
}
template <typename Archive, typename T>
void load(Archive& ar, ::boost::rational<T>& r, unsigned /*version*/)
{
int n, d;
ar & boost::serialization::make_nvp("numerator", n);
ar & boost::serialization::make_nvp("denominator", d);
r = ::boost::rational<T>(n, d);
}
} }
BOOST_SERIALIZATION_SPLIT_FREE(boost::rational<int>);
using namespace boost;
#include <iostream>
#include <sstream>
int main()
{
rational<int> number(2, 3), other;
std::stringstream ss;
{
archive::xml_oarchive oa(ss);
oa << serialization::make_nvp("rational", number);
}
std::cout << "Serialized: '" << ss.str() << "'\n";
{
archive::xml_iarchive ia(ss);
ia >> serialization::make_nvp("rational", other);
}
std::cout << "Deserialized: " << other;
}
Prints
Serialized: '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="10">
<rational class_id="0" tracking_level="0" version="0">
<numerator>2</numerator>
<denominator>3</denominator>
</rational>
</boost_serialization>
'
Deserialized: 2/3

Use the provided input/output functions: https://www.boost.org/doc/libs/1_64_0/libs/rational/rational.html#Input%20and%20Output
Serialize to a std::string:
template <typename I>
std::string serialize(boost::rational<I>& rational) const {
std::stringstream rational_ss;
rational_ss << rational;
return rational_ss.str();
}
This serializes the rational to a string that looks like "3/5" e.g.
To deserialize, use boost::rational's >>.

Related

Does std::find use operator== for std::vector<std::pair<T, T>>?

I tried to overload operator== for std::pair<int, int> so that only the first element of the pair would matter. Then, I'd like to use std::find to look for a particular element in std::vector<std::pair<int, int>>, using the overloaded operator==. But, it seems that, std::find is not using my overloaded operator==, though it is working in a simple comparison statement.
I expect the following code to output:
1
1
1
but I get:
1
1
0
Run on Linux, gcc 11.3:
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
using namespace std;
typedef pair<int, int> p_int_t;
bool operator==(const p_int_t& p1, const p_int_t& p2)
{
return p1.first == p2.first;
}
int main()
{
vector<p_int_t> v;
v.push_back({1, 2});
v.push_back({1, 3});
p_int_t p(1, 4);
cout << (v[0] == p) << endl;
cout << (v[1] == p) << endl;
cout << (find(v.begin(), v.end(), p) != v.end()) << endl;
return 0;
}
The compiler does not select the free standing comparison operator because the type p_int_t is an alias, and it is not defined in the std namespace as std:: pair is. In other words, the compiler is looking for an operator with this signature: std::operator==(const std::pair<int, int>&, const std::pair<int, int>&); and finds it in algorithm.
You could declare your operator in the std namespace, which works, but is not recommended, or define p_int_t as a class, as in:
#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>
using namespace std;
struct p_int_t : pair<int, int> {
using pair<int, int>::pair; // for c++=11 and later
p_int_t() : pair() {} // for c++98
p_int_t(int x, int y) : pair(x, y) {} // for c++98
friend bool operator==(const p_int_t& p1, const p_int_t& p2) {
return p1.first == p2.first;
}
};
int main() {
vector<p_int_t> v;
v.push_back({1, 2});
v.push_back({1, 3});
p_int_t p(1, 4);
cout << (v[0] == p) << endl;
cout << (v[1] == p) << endl;
cout << (find(v.begin(), v.end(), p) != v.end()) << endl;
return 0;
}
Code can be found here: https://godbolt.org/z/5dfPaaoMz
Having to redefine constructors is quite cumbersome, but you can also use std::find_if(), as in:
#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>
using namespace std;
typedef pair<int, int> p_int_t;
struct compare_first {
p_int_t p;
compare_first(p_int_t x) : p(x) {}
bool operator()(const p_int_t& x) { return x.first == p.first; }
};
int main() {
vector<p_int_t> v;
v.push_back({1, 2});
v.push_back({1, 3});
p_int_t p(1, 4);
cout << (find_if(v.begin(), v.end(), compare_first(p)) != v.end()) << endl;
// or for c++11 or later...
cout << (find_if(v.begin(), v.end(), [&p](const p_int_t& x) { return p.first == x.first; }) != v.end()) << endl;
return 0;
}
Code here: https://godbolt.org/z/r87hdrrK9

Defining strict_real_policies for reals with a comma decimal character

I would like to create a custom policy derived from strict_real_policies that will parse reals, such as "3,14", i.e. with a comma decimal point as used e.g. in Germany.
That should be easy, right?
#include <iostream>
#include <string>
#include <boost/spirit/home/x3.hpp>
template <typename T>
struct decimal_comma_strict_real_policies:boost::spirit::x3::strict_real_policies<T>
{
template <typename Iterator>
static bool
parse_dot(Iterator& first, Iterator const& last)
{
if (first == last || *first != ',')
return false;
++first;
return true;
}
};
void parse(const std::string& input)
{
namespace x3=boost::spirit::x3;
std::cout << "Parsing '" << input << "'" << std::endl;
std::string::const_iterator iter=std::begin(input),end=std::end(input);
const auto parser = x3::real_parser<double, decimal_comma_strict_real_policies<double>>{};
double parsed_num;
bool result=x3::parse(iter,end,parser,parsed_num);
if(result && iter==end)
{
std::cout << "Parsed: " << parsed_num << std::endl;
}
else
{
std::cout << "Something failed." << std::endl;
}
}
int main()
{
parse("3,14");
parse("3.14");
}

Refine mesh obtained with CGAL::Advancing_front_surface_reconstruction

I reconstruct a 3D surface mesh using the advancing front surface reconstruction and would like to refine it. How can I achieve this?
This is part of the code used for surface reconstruction with refinement by passing through a file:
#include <CGAL/Advancing_front_surface_reconstruction.h>
#include <CGAL/compute_average_spacing.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Triangulation_data_structure_3.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/Polygon_mesh_processing/refine.h>
#include <CGAL/Polygon_mesh_processing/fair.h>
typedef CGAL::Advancing_front_surface_reconstruction<> Reconstruction;
typedef Reconstruction::Triangulation_3 Triangulation_3;
typedef Reconstruction::Triangulation_data_structure_2 TDS_2;
typedef Reconstruction::Outlier_range Outlier_range;
typedef Reconstruction::Boundary_range Boundary_range;
typedef Reconstruction::Vertex_on_boundary_range Vertex_on_boundary_range;
typedef Reconstruction::Vertex_handle Vertex_handle;
typedef CGAL::Polyhedron_3<CGALMesher::Kernel> Polyhedron;
typedef CGAL::Surface_mesh<CGALMesher::Point> Mesh;
typedef CGAL::cpp11::array<std::size_t,3> Facet;
struct Construct {
Mesh& mesh;
template<typename PointIterator>
Construct(Mesh& mesh, PointIterator b, PointIterator e) : mesh(mesh) {
for (; b != e; ++b) {
boost::graph_traits<Mesh>::vertex_descriptor v;
v = add_vertex(mesh);
mesh.point(v) = *b;
}
}
Construct& operator=(const Facet f) {
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Mesh>::vertices_size_type size_type;
mesh.add_face(vertex_descriptor(static_cast<size_type>(f[0])),
vertex_descriptor(static_cast<size_type>(f[1])),
vertex_descriptor(static_cast<size_type>(f[2])));
return *this;
}
Construct&
operator*() {
return *this;
}
Construct&
operator++() {
return *this;
}
Construct operator++(int) {
return *this;
}
};
void CGALMesher::AdvancingFrontMesher(std::vector<Point>& points) {
Mesh m;
Construct construct(m,points.begin(),points.end());
CGAL::advancing_front_surface_reconstruction(points.begin(), points.end(), construct);
std::ofstream mesh_off("mesh.off");
mesh_off << m;
mesh_off.close();
std::ifstream input("mesh.off");
Polyhedron poly;
if ( !input || !(input >> poly) || poly.empty() ) {
std::cerr << "Not a valid off file." << std::endl;
}
input.close();
std::vector<Polyhedron::Facet_handle> new_facets;
std::vector<Polyhedron::Vertex_handle> new_vertices;
CGAL::Polygon_mesh_processing::refine(poly,
faces(poly),
std::back_inserter(new_facets),
std::back_inserter(new_vertices),
CGAL::Polygon_mesh_processing::parameters::density_control_factor(3));
std::ofstream refined_off("refined.off");
refined_off << poly;
refined_off.close();
std::cout << "Refinement added " << new_vertices.size() << " vertices." << std::endl;
}
Once you extracted a polyhedral surface out of the reconstruction algorithm, you can use the refine() function from the polygon mesh processing package. There is also the possibility to use the fair().
More drastically, you can use remeshing algorithm like this one. In CGAL 4.8, there will also be the function isotropic_remeshing() that is already available in the master branch.

C++: undefined reference to function - fails if header included and works if source included

I'm not able to make this code work using fellowed convention of header includes.
help.cpp
#include <iostream>
#include "basicMath.h"
using namespace std;
int main() {
int arr[4]={0,1,2,3};
int k=0;
int m=3;
//permutations call
perm(arr,k,m);
return 0;
}
BasicMath.h
#ifndef BASICMATH_H_
#define BASICMATH_H_
template<class T>
void Swap ( T& a, T& b );
template<class T1>
void perm ( T1 arr[], int k, int m);
#endif /* BASICMATH_H_ */
BasicMath.cpp
#include <iostream>
#include "basicMath.h"
using namespace std;
template<class T>
void Swap ( T& a, T& b )
{
T temp;
b=temp;
b=a;
a=temp;
}
template<class T1>
void perm ( T1 arr[], int k, int m)
{
//base case
cout << "Call: " << arr[0] << arr[1] << arr[2] << arr[3] << "\t" << k << "\t" << m << "\n";
if (k==m) {
for (int i=0;i<=m;i++) {
cout << arr[i];
}
cout << endl;
} else {
for (int i=k;i<=m;i++) {
swap(arr[k],arr[i]);
perm(arr,k+1,m);
swap(arr[k],arr[i]);
}
}
}
IF I replace the #include "basicMath.h" by #include "basicMath.cpp" Then program works.
Please help. New to Eclipse Project using headers and src.
Thanks in Adv.
The "simple" answer is that you can't put the implementation of a template function into a .cpp file.
See http://www.parashift.com/c++-faq/templates-defn-vs-decl.html

boost multi_index_container serialization

I am trying to use the boost::multi_index_container with the boost::serialization. However when I use Pointer to objects as elements and a non_unique order, I get a memory access violation loading the serialized container. I find it interesting that the error doesn't occur for unique ordering or using objects instead of pointers as container elements.
Can somebody tell me if there is a problem with my code or if this is a bug in the boost library?
Here is a minimal example that produces the described error:
#include <boost/multi_index_container.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/set.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <fstream>
using namespace std;
using namespace boost::multi_index;
struct element {
friend class boost::serialization::access;
std::string member1;
element( int num ) { member1 = boost::lexical_cast<string>( num ); }
element() {}
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & member1;
}
};
int main( int argc, const char *argv[] )
{
typedef multi_index_container<element *, indexed_by<ordered_non_unique<member<element, std::string, &element::member1>>>> TestSet;
TestSet myset;
srand( time (NULL ));
for (int i = 0; i < 20; i++) {
myset.insert(new element(rand()));
}
// Write set
ofstream os("test.bin");
boost::archive::binary_oarchive boa(os);
boa << myset;
os.close();
// Read set
TestSet newset;
ifstream is("test.bin");
boost::archive::binary_iarchive bia(is);
bia >> newset;
return 0;
}
ofstream os("test.bin"); should be:
ofstream os("test.bin", ios::binary);
Also:
ifstream is("test.bin"); should be: ifstream is("test.bin", ios::binary);