[graph] [beginner] How to use the "tie(...) feature" with standard c++ containers?

Hi recently i started programming with the boost graph library. You can use nice syntax for iterating over a set of vertices or edges by writing for example: //begin program #include <iostream> #include <boost/graph/adjacency_list.hpp> typedef boost::adjacency_list < boost::listS, boost::vecS, boost::bidirectionalS> my_graph; typedef boost::graph_traits <my_graph> my_graph_traits; int main() { my_graph g(5); my_graph_traits::vertex_iterator vi, vi_end; for (boost::tie (vi, vi_end) = vertices (g); vi != vi_end; ++vi) { std::cout << "vertex: " << *vi << std::endl; } } //End program Outputs: vertex: 0 vertex: 1 vertex: 2 vertex: 3 vertex: 4 My question is now how to define functions 'tie(...)' and 'elements(...)' for using them with standard containers. Suppose you have a container like the list: std::list <unsigned int> list(4); Now to iterate over all elements i would like to write something like //begin snippet std::list <unsigned int>::iterator begin, end; for (tie (begin, end) = elements (list); begin != end; ++begin) ;// do some thing //end snippet In stead of writing: //begin snippet begin = list.begin(); end = list.end(); for (; begin != end; ++begin) ;// do some thing //end snippet I started defining the function elements(...) like this: template <typename T> std::pair < typename T::iterator, typename T::iterator> elements (T container) { return std::make_pair(container.begin(), container.end()); } The compiler tells me, that 'tie' was not declared in this scope. So i assume that i also have to define the 'tie' function in some way. Maybe there is already some functionality to access the standard containers the way you can do it with 'tie' or maybe you could give me some hint to solve the problem. best regards Christoph

i just found http://www.boost.org/doc/libs/1_47_0/doc/html/foreach.html from the docs: For example, we can use BOOST_FOREACH with: - STL containers - arrays - Null-terminated strings (char and wchar_t) - std::pair of iterators This way i can use one simple Expression for lists std::list<int> list_int( /*...*/ ); BOOST_FOREACH( int i, list_int ) { // do something with i } or for vertices in graphs: BOOST_FOREACH(my_graph_traits::vertex_descriptor vi, vertices (g)) { std::cout << vi << std::endl; } even though the original question is still there...

On Sun, 9 Oct 2011, Christoph wrote:
Hi
recently i started programming with the boost graph library. You can use nice syntax for iterating over a set of vertices or edges by writing for example:
//begin program #include <iostream> #include <boost/graph/adjacency_list.hpp>
typedef boost::adjacency_list < boost::listS, boost::vecS, boost::bidirectionalS> my_graph;
typedef boost::graph_traits <my_graph> my_graph_traits;
int main() { my_graph g(5); my_graph_traits::vertex_iterator vi, vi_end;
for (boost::tie (vi, vi_end) = vertices (g); vi != vi_end; ++vi) { std::cout << "vertex: " << *vi << std::endl; } } //End program
Outputs: vertex: 0 vertex: 1 vertex: 2 vertex: 3 vertex: 4
My question is now how to define functions 'tie(...)' and 'elements(...)' for using them with standard containers.
Suppose you have a container like the list:
std::list <unsigned int> list(4);
Now to iterate over all elements i would like to write something like
//begin snippet std::list <unsigned int>::iterator begin, end; for (tie (begin, end) = elements (list); begin != end; ++begin) ;// do some thing //end snippet
In stead of writing:
//begin snippet begin = list.begin(); end = list.end();
for (; begin != end; ++begin) ;// do some thing //end snippet
I started defining the function elements(...) like this:
template <typename T> std::pair < typename T::iterator, typename T::iterator> elements (T container) { return std::make_pair(container.begin(), container.end()); }
The compiler tells me, that 'tie' was not declared in this scope. So i assume that i also have to define the 'tie' function in some way. Maybe there is already some functionality to access the standard containers the way you can do it with 'tie' or maybe you could give me some hint to solve the problem.
You need to use boost::tie if your iterator types are not already in the boost namespace. The definition of tie is in Boost.Tuple, I think. -- Jeremiah Willcock

[...]
You need to use boost::tie if your iterator types are not already in the boost namespace. The definition of tie is in Boost.Tuple, I think.
Thank you Jeremiah for pointing that out. I think i still have my problems with ADL and name spaces... Off course ADL (Argument Dependant Name Lookup) will not find any definition for 'tie' with the arguments being in the name space 'std', because 'tie' is defined in the name space 'boost' and not in the name space 'std'. So here is an unhappy example in which i write 'boost::tie' in stead of just 'tie' which compiles without errors but does not do what i expected: // begin code #include <iostream> #include <boost/graph/adjacency_list.hpp> typedef boost::adjacency_list < boost::listS, boost::vecS, boost::bidirectionalS> my_graph; typedef boost::graph_traits <my_graph> my_graph_traits; template <typename T> boost::tuple < typename T::iterator, typename T::iterator> elements (T container) { typename T::iterator beg = container.begin(); typename T::iterator end = container.end(); for (;beg != end; ++beg) std::cout << *beg << ": loop in elements()" << std::endl; return boost::make_tuple(container.begin(), container.end()); } int main () { std::list <int> list; list.push_back(1);list.push_back(2); list.push_back(3);list.push_back(4); std::list <int>::iterator beg, end; int i = 0; /* uncomment for testing purpose for (boost::tie(beg, end) = elements <std::list<int> >(list); beg != end; ++beg) { std::cout << *beg << ", i = " << i++ << std::endl; }*/ beg = list.begin(); end = list.end(); for(; beg != end; ++beg) std::cout << *beg << ", i = " << i++ << std::endl; return 0; } // end code If you compile and run the code as it is the output is: 1, i = 0 2, i = 1 3, i = 2 4, i = 3 However if you uncomment the 'for-loop' part and leave the rest of the code as it is, compile and run, than the output will be: 1: loop in elements() 2: loop in elements() 3: loop in elements() 4: loop in elements() 1, i = 0 I expected the output to be: 1: loop in elements() 2: loop in elements() 3: loop in elements() 4: loop in elements() 1, i = 0 2, i = 1 3, i = 2 4, i = 3 1, i = 0 2, i = 1 3, i = 2 4, i = 3 I do not get it. Maybe you could help me to find out. best regards again Christoph

Hi, On Monday, 10. October 2011 11:04:38 Christoph wrote:
[...]
You need to use boost::tie if your iterator types are not already in the boost namespace. The definition of tie is in Boost.Tuple, I think.
Thank you Jeremiah for pointing that out. I think i still have my problems with ADL and name spaces... Off course ADL (Argument Dependant Name Lookup) will not find any definition for 'tie' with the arguments being in the name space 'std', because 'tie' is defined in the name space 'boost' and not in the name space 'std'.
So here is an unhappy example in which i write 'boost::tie' in stead of just 'tie' which compiles without errors but does not do what i expected:
// begin code
#include <iostream> #include <boost/graph/adjacency_list.hpp>
typedef boost::adjacency_list < boost::listS, boost::vecS, boost::bidirectionalS> my_graph;
typedef boost::graph_traits <my_graph> my_graph_traits;
template <typename T> boost::tuple < typename T::iterator, typename T::iterator> elements (T container)
Please note that you are using a _copy_ here and thus you also return the iterators of a _copy_ but not of the "original" container. Therefore, I assume that the iterators returned are not valid and might even lead to a segmentation fault (as they do on my machine, since this container-copy is only valid during the execution of elements() ). Perhaps you want to try "const T& container" in the argument list. When I use that, I get: 1: loop in elements() 2: loop in elements() 3: loop in elements() 4: loop in elements() 1, i = 0 2, i = 1 3, i = 2 4, i = 3 1, i = 4 2, i = 5 3, i = 6 4, i = 7
{ typename T::iterator beg = container.begin(); typename T::iterator end = container.end(); for (;beg != end; ++beg) std::cout << *beg << ": loop in elements()" << std::endl; return boost::make_tuple(container.begin(), container.end()); }
int main () { std::list <int> list; list.push_back(1);list.push_back(2); list.push_back(3);list.push_back(4);
std::list <int>::iterator beg, end; int i = 0;
/* uncomment for testing purpose for (boost::tie(beg, end) = elements <std::list<int> >(list); beg != end; ++beg) { std::cout << *beg << ", i = " << i++ << std::endl; }*/
beg = list.begin(); end = list.end(); for(; beg != end; ++beg) std::cout << *beg << ", i = " << i++ << std::endl; return 0; } // end code
If you compile and run the code as it is the output is: 1, i = 0 2, i = 1 3, i = 2 4, i = 3
However if you uncomment the 'for-loop' part and leave the rest of the code as it is, compile and run, than the output will be: 1: loop in elements() 2: loop in elements() 3: loop in elements() 4: loop in elements() 1, i = 0
I expected the output to be:
1: loop in elements() 2: loop in elements() 3: loop in elements() 4: loop in elements() 1, i = 0 2, i = 1 3, i = 2 4, i = 3 1, i = 0 2, i = 1 3, i = 2 4, i = 3
I do not get it. Maybe you could help me to find out.
Best, Cedric
best regards again Christoph
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Hi Cedric, On Mon, 2011-10-10 at 11:29 +0200, Cedric Laczny wrote: [...]
Please note that you are using a _copy_ here and thus you also return the iterators of a _copy_ but not of the "original" container. Therefore, I assume that the iterators returned are not valid and might even lead to a segmentation fault (as they do on my machine, since this container-copy is only valid during the execution of elements() ). Perhaps you want to try "const T& container" in the argument list.
The bright shine of conclusion comes over me. I feel a little bit less stupid for a moment... The felling is gone. By using the "&"-reference type the operations in 'elements' are done on 'the original'. Now a 2-tuple of std::list <int>::iterator of 'the original' list is returned by 'elements'. For completeness here is the not so unhappy example in which i use 'T&' in stead of 'const T&' in stead of 'T' as the argument of function 'elements': // begin code #include <iostream> #include <list> #include <boost/tuple/tuple.hpp> template <typename T> boost::tuple < typename T::iterator, typename T::iterator> elements ( T& container) { return boost::make_tuple(container.begin(), container.end()); } int main () { std::list <int> list; list.push_back(1); list.push_back(2); list.push_back(3); list.push_back(4); std::list <int>::iterator beg, end; for (boost::tie(beg, end) = elements <std::list<int> >(list); beg != end; ++beg) { std::cout << *beg << std::endl; } return 0; } // end code Output is: 1 2 3 4 Thank you all for clearing things up. Christoph
participants (3)
-
Cedric Laczny
-
Christoph
-
Jeremiah Willcock