Trying to make a container of templated functions

I am trying to parse a .obj file. .obj files are ascii, and basically a set of pairs: keyword - value :
v 1 2 3
vn 1 2
...

where "v" and "vn" are keywords and "1 2 3" and "1 2" are values.


Right now I am in the early stages, just going through the .obj specs and making various structs to hold data.

To test my code, I have a little console input program. I type "v 1 2 3", and the vector associated with keyword "v" gets added the value 1 2 3.

I have a map of functions:
1
2
3
4
5
6
7
8
9
10
using read_func = std::function< void ( std::istream& )>;
using func_map  = std::map< const std::string, const read_func >; // const read_func?

const func_map functions = {
    { "v" ,     read_vertex  },
    { "vn",     read_normal  },
    { "vt",     read_texture },
    { "cstype", read_curve   },
    { "deg",    read_degree  }
};


Of course, I'm writing very similar code for each of the read_funcs. I templated the function
1
2
template <typename T>
void read_vector( std::vector<T>&, std::istream& );


But now I have issues with the std::function.

Is it possible to templatize this, perhaps end with something like this:
1
2
3
4
5
6
7
const func_map functions = {
    { "v" ,     read_vector( vertecies ) },
    { "vn",     read_vector( normals   ) },
    { "vt",     read_vector( textures  ) },
    { "cstype", read_vector( curves    ) },
    { "deg",    read_vector( degrees   ) }
};


Thanks.

Also, I read that const will make the code optimize better, so I'm on a "const kick". Is it a valid thought that "everything that doesn't change should be const".

Edit: I moved along, and came up with this:
1
2
3
4
5
6
7
8
9
10
11
12
template <typename T>
void read_vector(std::vector<T> vect, std::istream& in = std::cin)
{
    T temp;
    in >> temp;
    vect.emplace_back(temp);
}
 
void read_vertex( std::istream& in = std::cin){
    read_vector( geometry_vector, in );
}
/* ... */

Reduces my copy/paste a little.
Last edited on
I am not sure to understand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class read_vector{
   vector &v;
public:
   read_vector( vector &v ): v(v){}
   void operator()(std::istream &input){
      //reading
   }
};

std::map< std::string, read_vector > functions = {
    { "v" ,     read_vector( vertecies ) },
    { "vn",     read_vector( normals   ) },
    { "vt",     read_vector( textures  ) },
    { "cstype", read_vector( curves    ) },
    { "deg",    read_vector( degrees   ) }
};
Or use std::bind()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
template< typename CONTAINER >
std::istream& read_sequence( std::istream& stm, CONTAINER& seq )
{
    typename CONTAINER::value_type v ;
    while( stm >> v ) seq.push_back(v) ;
    return stm ;
}

template< typename CONTAINER >
std::function< std::istream& ( std::istream& ) > bind_container( CONTAINER& seq )
{ return std::bind( read_sequence<CONTAINER>, std::placeholders::_1, std::ref(seq) ) ; }

std::vector<int> vec1 ;
std::vector<long long> vec2 ;
std::deque<double> deq ;
std::list<short> lst ;

std::map< std::string, std::function< std::istream& ( std::istream& ) > > func_map
{
     { "abc", bind_container(vec1) },
     { "defgh", bind_container(vec2) },
     { "ijkl", bind_container(deq) },
     { "mn", bind_container(lst) }
};

@ ne555: It looks like this could work. I'm not sure about how to use this with vectors that hold different types of data though.

@ JLBorges: Yes, this is exactly what I would have had in mind if I could think of it.

Amazing that it can keep different typed containers too ( as well as the type the containers hold ).

So, std::placeholders::_1 will allow me to call the function with any type of istream?

Pretty neat, thanks.
Last edited on
Topic archived. No new replies allowed.