2#include <gtest/gtest.h>
3#include <OpenMesh/Core/Utils/PropertyManager.hh>
4#include <Unittests/unittests_common.hh>
7#include "generate_cube.hh"
8#include "fill_props.hh"
24 : ival(0), dval(0.0), bval(
false), vec4fval(0.0,0.0,0.0,0.0)
28 : ival(_cpy.ival), dval(_cpy.dval), bval(_cpy.bval),
29 vec4fval(_cpy.vec4fval)
39 vec4fval = _rhs.vec4fval;
43 MyData& operator = (
int _rhs) { ival = _rhs;
return *
this; }
44 MyData& operator = (
double _rhs) { dval = _rhs;
return *
this; }
45 MyData& operator = (
bool _rhs) { bval = _rhs;
return *
this; }
47 { vec4fval = _rhs;
return *
this; }
51 bool operator == (
const MyData& _rhs)
const
53 return ival == _rhs.ival
56 && vec4fval == _rhs.vec4fval;
58 bool operator != (
const MyData& _rhs)
const {
return !(*
this == _rhs); }
61typedef std::map< std::string, unsigned int > MyMap;
83 static size_t store(std::ostream& _os,
const value_type& _v,
bool _swap=
false)
86 bytes = IO::store( _os, _v.ival, _swap );
87 bytes += IO::store( _os, _v.dval, _swap );
88 bytes += IO::store( _os, _v.bval, _swap );
89 bytes += IO::store( _os, _v.vec4fval, _swap );
90 return _os.good() ? bytes : 0;
96 bytes = IO::restore( _is, _v.ival, _swap );
97 bytes += IO::restore( _is, _v.dval, _swap );
98 bytes += IO::restore( _is, _v.bval, _swap );
99 bytes += IO::restore( _is, _v.vec4fval, _swap );
100 return _is.good() ? bytes : 0;
106 typedef MyMap value_type;
110 static size_t size_of(
void) {
return UnknownSize; }
113 static size_t size_of(
const value_type& _v)
116 return sizeof(
unsigned int);
118 value_type::const_iterator it = _v.begin();
119 unsigned int N = _v.size();
121 for(;it!=_v.end(); ++it)
131 size_t store(std::ostream& _os,
const value_type& _v,
bool _swap=
false)
134 unsigned int N = _v.size();
135 value_type::const_iterator it = _v.begin();
136 bytes += IO::store( _os, N, _swap );
137 for (; it != _v.end() && _os.good(); ++it)
139 bytes += IO::store( _os, it->first, _swap );
140 bytes += IO::store( _os, it->second, _swap );
142 return _os.good() ? bytes : 0;
146 size_t restore( std::istream& _is, value_type& _v,
bool _swap=
false)
151 bytes += IO::restore( _is, N, _swap );
152 value_type::key_type key;
153 value_type::mapped_type val;
154 for (
size_t i=0; i<N && _is.good(); ++i)
156 bytes += IO::restore( _is, key, _swap );
157 bytes += IO::restore( _is, val, _swap );
160 return _is.good() ? bytes : 0;
174 virtual void SetUp() {
180 virtual void TearDown() {
195template <
class Mesh>
class SmootherT
203 explicit SmootherT(
Mesh& _mesh)
206 mesh_.add_property( cog_ );
210 mesh_.remove_property( cog_ );
213 void smooth(
unsigned int _iterations)
215 for (
unsigned int i=0; i < _iterations; ++i)
217 std::for_each(mesh_.vertices_begin(),
218 mesh_.vertices_end(),
219 ComputeCOG(mesh_, cog_));
220 std::for_each(mesh_.vertices_begin(),
221 mesh_.vertices_end(),
222 SetCOG(mesh_, cog_));
231 ComputeCOG(
Mesh& _mesh, Property_cog& _cog)
232 : mesh_(_mesh), cog_(_cog)
239 mesh_.property(cog_, _vh) =
typename Mesh::Point(0.0, 0.0, 0.0);
240 for (vv_it=mesh_.vv_iter(_vh); vv_it.is_valid(); ++vv_it)
242 mesh_.property(cog_, _vh) += mesh_.point( *vv_it );
245 mesh_.property(cog_, _vh ) /= valence;
255 SetCOG(
Mesh& _mesh, Property_cog& _cog)
256 : mesh_(_mesh), cog_(_cog)
260 if (!mesh_.is_boundary(_vh))
261 mesh_.set_point( _vh, mesh_.property(cog_, _vh) );
310 VertexT() : cog_( Point(0.0f, 0.0f, 0.0f ) ) { }
311 const Point& cog()
const {
return cog_; }
312 void set_cog(
const Point& _p) { cog_ = _p; }
343TEST_F(OpenMeshTutorials, building_a_cube) {
359 std::vector<MyMesh::VertexHandle> face_vhandles;
360 face_vhandles.clear();
361 face_vhandles.push_back(vhandle[0]);
362 face_vhandles.push_back(vhandle[1]);
363 face_vhandles.push_back(vhandle[2]);
364 face_vhandles.push_back(vhandle[3]);
365 mesh.add_face(face_vhandles);
367 face_vhandles.clear();
368 face_vhandles.push_back(vhandle[7]);
369 face_vhandles.push_back(vhandle[6]);
370 face_vhandles.push_back(vhandle[5]);
371 face_vhandles.push_back(vhandle[4]);
372 mesh.add_face(face_vhandles);
373 face_vhandles.clear();
374 face_vhandles.push_back(vhandle[1]);
375 face_vhandles.push_back(vhandle[0]);
376 face_vhandles.push_back(vhandle[4]);
377 face_vhandles.push_back(vhandle[5]);
378 mesh.add_face(face_vhandles);
379 face_vhandles.clear();
380 face_vhandles.push_back(vhandle[2]);
381 face_vhandles.push_back(vhandle[1]);
382 face_vhandles.push_back(vhandle[5]);
383 face_vhandles.push_back(vhandle[6]);
384 mesh.add_face(face_vhandles);
385 face_vhandles.clear();
386 face_vhandles.push_back(vhandle[3]);
387 face_vhandles.push_back(vhandle[2]);
388 face_vhandles.push_back(vhandle[6]);
389 face_vhandles.push_back(vhandle[7]);
390 mesh.add_face(face_vhandles);
391 face_vhandles.clear();
392 face_vhandles.push_back(vhandle[0]);
393 face_vhandles.push_back(vhandle[3]);
394 face_vhandles.push_back(vhandle[7]);
395 face_vhandles.push_back(vhandle[4]);
396 mesh.add_face(face_vhandles);
400 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'output.off'";
403TEST_F(OpenMeshTutorials, using_iterators_and_circulators) {
408 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'output.off'";
411 std::vector<MyMesh::Point> cogs;
412 std::vector<MyMesh::Point>::iterator cog_it;
413 cogs.reserve(mesh.n_vertices());
420 unsigned int i, N(100);
421 for (i=0; i < N; ++i)
424 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
426 cog[0] = cog[1] = cog[2] = valence = 0.0;
428 for (vv_it = mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it)
430 cog += mesh.point( *vv_it );
433 cogs.push_back(cog / valence);
436 for (v_it = mesh.vertices_begin(), cog_it = cogs.begin();
437 v_it != v_end; ++v_it, ++cog_it)
438 if ( !mesh.is_boundary( *v_it ) )
439 mesh.set_point( *v_it, *cog_it );
445 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'smoothed_output.off'";
448TEST_F(OpenMeshTutorials, using_custom_properties) {
452 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'cube_noisy.off'";
454 const int iterations = 100;
461 for (
int i = 0; i < iterations; ++i) {
463 for (
const auto& vh : mesh.vertices()) {
467 for (
const auto& vvh : mesh.vv_range(vh)) {
468 cog[vh] += mesh.point(vvh);
474 for (
const auto& vh : mesh.vertices()) {
475 mesh.point(vh) = cog[vh];
483 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'smoothed_custom_properties_output.off'";
486TEST_F(OpenMeshTutorials, using_STL_algorithms) {
487 MyMeshWithTraits mesh;
490 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'cube_noisy.off'";
492 SmootherT<MyMeshWithTraits> smoother(mesh);
493 smoother.smooth(100);
498 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'smoothed_STL_output.off'";
501TEST_F(OpenMeshTutorials, using_standard_properties) {
504 mesh.request_vertex_normals();
505 EXPECT_TRUE(mesh.has_vertex_normals()) <<
"Standard vertex property 'Normals' not available";
509 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'output.off'";
515 mesh.request_face_normals();
519 mesh.release_face_normals();
524 v_it != mesh.vertices_end(); ++v_it)
526 mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) );
530 mesh.release_vertex_normals();
532 EXPECT_FALSE(mesh.has_vertex_normals()) <<
"Shouldn't have any vertex normals anymore";
535TEST_F(OpenMeshTutorials, using_mesh_attributes_and_traits) {
540 typeid(
double)) <<
"Data type is wrong";
544 typeid(
double)) <<
"Data type is wrong";
547 mesh.request_vertex_normals();
549 mesh.request_face_normals();
554 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'output.off'";
558 mesh.has_face_normals() && mesh.has_vertex_normals() )
566 v_it != mesh.vertices_end(); ++v_it)
568 mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) );
572TEST_F(OpenMeshTutorials, extending_the_mesh_using_traits) {
573 MyTriMeshWithCOG mesh;
576 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'output.off'";
579 MyTriMeshWithCOG::VertexIter v_it, v_end(mesh.vertices_end());
580 MyTriMeshWithCOG::VertexVertexIter vv_it;
581 MyTriMeshWithCOG::Point cog;
582 MyTriMeshWithCOG::Scalar valence;
583 unsigned int i, N(100);
585 for (i=0; i < N; ++i)
587 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
589 cog[0] = cog[1] = cog[2] = valence = 0.0;
591 for (vv_it = mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it)
593 cog += mesh.point( *vv_it );
596 mesh.data(*v_it).set_cog(cog / valence);
599 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
600 if (!mesh.is_boundary(*v_it))
601 mesh.set_point( *v_it, mesh.data(*v_it).cog());
607 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'smoothed_extended_output.off'";
611TEST_F(OpenMeshTutorials, deleting_geometry_elements) {
615 mesh.request_face_status();
616 mesh.request_edge_status();
617 mesh.request_vertex_status();
633 std::vector<Mesh::VertexHandle> tmp_face_vhandles;
634 tmp_face_vhandles.clear();
635 tmp_face_vhandles.push_back(vhandle[0]);
636 tmp_face_vhandles.push_back(vhandle[1]);
637 tmp_face_vhandles.push_back(vhandle[2]);
638 tmp_face_vhandles.push_back(vhandle[3]);
639 fhandle[0] = mesh.add_face(tmp_face_vhandles);
641 tmp_face_vhandles.clear();
642 tmp_face_vhandles.push_back(vhandle[7]);
643 tmp_face_vhandles.push_back(vhandle[6]);
644 tmp_face_vhandles.push_back(vhandle[5]);
645 tmp_face_vhandles.push_back(vhandle[4]);
646 fhandle[1] = mesh.add_face(tmp_face_vhandles);
648 tmp_face_vhandles.clear();
649 tmp_face_vhandles.push_back(vhandle[1]);
650 tmp_face_vhandles.push_back(vhandle[0]);
651 tmp_face_vhandles.push_back(vhandle[4]);
652 tmp_face_vhandles.push_back(vhandle[5]);
653 fhandle[2] = mesh.add_face(tmp_face_vhandles);
655 tmp_face_vhandles.clear();
656 tmp_face_vhandles.push_back(vhandle[2]);
657 tmp_face_vhandles.push_back(vhandle[1]);
658 tmp_face_vhandles.push_back(vhandle[5]);
659 tmp_face_vhandles.push_back(vhandle[6]);
660 fhandle[3] = mesh.add_face(tmp_face_vhandles);
661 tmp_face_vhandles.clear();
662 tmp_face_vhandles.push_back(vhandle[3]);
663 tmp_face_vhandles.push_back(vhandle[2]);
664 tmp_face_vhandles.push_back(vhandle[6]);
665 tmp_face_vhandles.push_back(vhandle[7]);
666 fhandle[4] = mesh.add_face(tmp_face_vhandles);
668 tmp_face_vhandles.clear();
669 tmp_face_vhandles.push_back(vhandle[0]);
670 tmp_face_vhandles.push_back(vhandle[3]);
671 tmp_face_vhandles.push_back(vhandle[7]);
672 tmp_face_vhandles.push_back(vhandle[4]);
673 fhandle[5] = mesh.add_face(tmp_face_vhandles);
679 EXPECT_FALSE(mesh.status(fhandle[0]).deleted()) <<
"face shouldn't be deleted";
680 EXPECT_FALSE(mesh.status(fhandle[1]).deleted()) <<
"face shouldn't be deleted";
681 EXPECT_FALSE(mesh.status(fhandle[2]).deleted()) <<
"face shouldn't be deleted";
682 EXPECT_FALSE(mesh.status(fhandle[3]).deleted()) <<
"face shouldn't be deleted";
683 EXPECT_FALSE(mesh.status(fhandle[4]).deleted()) <<
"face shouldn't be deleted";
684 EXPECT_FALSE(mesh.status(fhandle[5]).deleted()) <<
"face shouldn't be deleted";
687 mesh.delete_face(fhandle[0],
false);
689 mesh.delete_face(fhandle[2],
false);
691 mesh.delete_face(fhandle[3],
false);
693 mesh.delete_face(fhandle[4],
false);
695 mesh.delete_face(fhandle[5],
false);
697 EXPECT_TRUE(mesh.status(fhandle[0]).deleted()) <<
"face should be deleted";
698 EXPECT_FALSE(mesh.status(fhandle[1]).deleted()) <<
"face shouldn't be deleted";
699 EXPECT_TRUE(mesh.status(fhandle[2]).deleted()) <<
"face should be deleted";
700 EXPECT_TRUE(mesh.status(fhandle[3]).deleted()) <<
"face should be deleted";
701 EXPECT_TRUE(mesh.status(fhandle[4]).deleted()) <<
"face should be deleted";
702 EXPECT_TRUE(mesh.status(fhandle[5]).deleted()) <<
"face should be deleted";
710 EXPECT_FALSE(mesh.status(vhandle[0]).deleted()) <<
"vertex shouldn't be deleted";
711 EXPECT_FALSE(mesh.status(vhandle[1]).deleted()) <<
"vertex shouldn't be deleted";
712 EXPECT_FALSE(mesh.status(vhandle[2]).deleted()) <<
"vertex shouldn't be deleted";
713 EXPECT_FALSE(mesh.status(vhandle[3]).deleted()) <<
"vertex shouldn't be deleted";
716 mesh.delete_vertex(vhandle[0],
false);
717 mesh.delete_vertex(vhandle[1],
false);
718 mesh.delete_vertex(vhandle[2],
false);
719 mesh.delete_vertex(vhandle[3],
false);
722 EXPECT_TRUE(mesh.status(vhandle[0]).deleted()) <<
"vertex should be deleted";
723 EXPECT_TRUE(mesh.status(vhandle[1]).deleted()) <<
"vertex should be deleted";
724 EXPECT_TRUE(mesh.status(vhandle[2]).deleted()) <<
"vertex should be deleted";
725 EXPECT_TRUE(mesh.status(vhandle[3]).deleted()) <<
"vertex should be deleted";
729 mesh.garbage_collection();
734 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'deleted_output.off'";
738TEST_F(OpenMeshTutorials, storing_custom_properties) {
742 generate_cube<MyMesh>(mesh);
752 mesh.add_property(vprop_float,
"vprop_float");
753 mesh.add_property(eprop_bool,
"eprop_bool");
754 mesh.add_property(fprop_string,
"fprop_string");
755 mesh.add_property(hprop_mydata,
"hprop_mydata");
756 mesh.add_property(mprop_map,
"mprop_map");
759 fill_props(mesh, vprop_float);
760 fill_props(mesh, eprop_bool);
761 fill_props(mesh, fprop_string);
762 fill_props(mesh, hprop_mydata);
763 fill_props(mesh, mprop_map);
765 EXPECT_TRUE(fill_props(mesh, vprop_float,
true)) <<
"property not filled correctly";
766 EXPECT_TRUE(fill_props(mesh, eprop_bool,
true)) <<
"property not filled correctly";
767 EXPECT_TRUE(fill_props(mesh, fprop_string,
true)) <<
"property not filled correctly";
768 EXPECT_TRUE(fill_props(mesh, hprop_mydata,
true)) <<
"property not filled correctly";
769 EXPECT_TRUE(fill_props(mesh, mprop_map,
true)) <<
"property not filled correctly";
772 mesh.property(vprop_float).set_persistent(
true);
773 EXPECT_TRUE(mesh.property(vprop_float).persistent()) <<
"property should be persistent";
774 mesh.property(eprop_bool).set_persistent(
true);
775 EXPECT_TRUE(mesh.property(eprop_bool).persistent()) <<
"property should be persistent";
776 mesh.property(fprop_string).set_persistent(
true);
777 EXPECT_TRUE(mesh.property(fprop_string).persistent()) <<
"property should be persistent";
778 mesh.property(hprop_mydata).set_persistent(
true);
779 EXPECT_TRUE(mesh.property(hprop_mydata).persistent()) <<
"property should be persistent";
780 mesh.mproperty(mprop_map).set_persistent(
true);
781 EXPECT_TRUE(mesh.mproperty(mprop_map).persistent()) <<
"property should be persistent";
786 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'persistent-check.om'";
793 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'persistence-check.om'";
796 EXPECT_TRUE(fill_props(mesh, vprop_float,
true)) <<
"property not filled correctly";
797 EXPECT_TRUE(fill_props(mesh, eprop_bool,
true)) <<
"property not filled correctly";
798 EXPECT_TRUE(fill_props(mesh, fprop_string,
true)) <<
"property not filled correctly";
799 EXPECT_TRUE(fill_props(mesh, hprop_mydata,
true)) <<
"property not filled correctly";
800 EXPECT_TRUE(fill_props(mesh, mprop_map,
true)) <<
"property not filled correctly";
805TEST_F(OpenMeshTutorials, flipping_edges) {
814 std::vector<Mesh::VertexHandle> face_vhandles;
815 face_vhandles.push_back(vhandle[2]);
816 face_vhandles.push_back(vhandle[1]);
817 face_vhandles.push_back(vhandle[0]);
818 mesh.add_face(face_vhandles);
819 face_vhandles.clear();
820 face_vhandles.push_back(vhandle[2]);
821 face_vhandles.push_back(vhandle[0]);
822 face_vhandles.push_back(vhandle[3]);
823 mesh.add_face(face_vhandles);
827 for(
Mesh::EdgeIter it = mesh.edges_begin(); it != mesh.edges_end(); ++it) {
828 if(!mesh.is_boundary(*it)) {
830 EXPECT_EQ(vhandle[2].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,0)).idx()) <<
"expected vertex handle 2!" ;
831 EXPECT_EQ(vhandle[0].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,1)).idx()) <<
"expected vertex handle 0!" ;
833 EXPECT_EQ(vhandle[1].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,0)).idx()) <<
"expected vertex handle 1 (did the flip work?)!" ;
834 EXPECT_EQ(vhandle[3].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,1)).idx()) <<
"expected vertex handle 3 (did the flip work?)!" ;
842TEST_F(OpenMeshTutorials, collapsing_edges) {
844 mesh.request_vertex_status();
845 mesh.request_edge_status();
847 PolyMesh::VertexHandle vhandle[7];
856 std::vector<PolyMesh::VertexHandle> face_vhandles;
857 face_vhandles.push_back(vhandle[1]);
858 face_vhandles.push_back(vhandle[0]);
859 face_vhandles.push_back(vhandle[2]);
860 face_vhandles.push_back(vhandle[3]);
861 mesh.add_face(face_vhandles);
862 face_vhandles.clear();
863 face_vhandles.push_back(vhandle[1]);
864 face_vhandles.push_back(vhandle[3]);
865 face_vhandles.push_back(vhandle[5]);
866 face_vhandles.push_back(vhandle[4]);
867 mesh.add_face(face_vhandles);
868 face_vhandles.clear();
869 face_vhandles.push_back(vhandle[3]);
870 face_vhandles.push_back(vhandle[2]);
871 face_vhandles.push_back(vhandle[6]);
872 face_vhandles.push_back(vhandle[5]);
873 mesh.add_face(face_vhandles);
877 if( mesh.to_vertex_handle(*it) == vhandle[3] &&
878 mesh.from_vertex_handle(*it) == vhandle[2])
888TEST_F(OpenMeshTutorials, using_smart_handles_and_smart_ranges) {
892 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'cube_noisy.off'";
894 const int iterations = 100;
904 auto points = OpenMesh::getPointsProperty(mesh);
907 for (
int i = 0; i < iterations; ++i) {
909 for (
const auto& vh : mesh.vertices())
910 laplace(vh) = vh.vertices().avg(points) - points(vh);
913 for (
const auto& vh : mesh.vertices())
914 bi_laplace(vh) = (vh.vertices().avg(laplace) - laplace(vh));
917 for (
const auto& vh : mesh.vertices())
918 points(vh) += -0.5 * bi_laplace(vh);
925 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'smoothed_smart_output.off'";
#define VertexAttributes(_i)
Macro for defining the vertex attributes. See Specifying your MyMesh.
#define FaceAttributes(_i)
Macro for defining the face attributes. See Specifying your MyMesh.
#define EdgeAttributes(_i)
Macro for defining the edge attributes. See Specifying your MyMesh.
#define VertexTraits
Macro for defining the vertex traits. See Specifying your MyMesh.
Set options for reader/writer modules.
@ VertexNormal
Has (r) / store (w) vertex normals.
@ Custom
Has (r) / store (w) custom properties marked persistent (currently PLY only supports reading and only...
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Kernel::Scalar Scalar
Scalar type.
void update_normals()
Compute normals for all primitives.
SmartVertexHandle add_vertex(const Point _p)
Kernel::FaceHandle FaceHandle
Scalar type.
Kernel::EdgeIter EdgeIter
Scalar type.
Kernel::VertexVertexIter VertexVertexIter
Circulator.
Kernel::HalfedgeIter HalfedgeIter
Scalar type.
Kernel::Point Point
Coordinate type.
Kernel::VertexIter VertexIter
Scalar type.
@ Status
Add status to mesh item (all items)
@ PrevHalfedge
Add storage for previous halfedge (halfedges). The bit is set by default in the DefaultTraits.
bool write_mesh(const Mesh &_mesh, const std::string &_filename, Options _opt=Options::Default, std::streamsize _precision=6)
Write a mesh to the file _filename.
size_t size_of(const T &_v)
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
Vec3f Point
The default coordinate type is OpenMesh::Vec3f.
Vec3f Normal
The default normal type is OpenMesh::Vec3f.
static size_t restore(std::istream &, value_type &, bool=false, bool=true)
Restore a value of T and return the number of bytes read.
static const bool is_streamable
Can we store T? Set this to true in your specialization.
static size_t store(std::ostream &, const value_type &, bool=false, bool=true)
Store a value of T and return the number of bytes written.
static std::string type_identifier(void)
A string that identifies the type of T.
static size_t size_of(void)
What's the size of T? If it depends on the actual value (e.g. for vectors) return UnknownSize.
T::value_type value_type
Type of the scalar value.