c++11 - C++: Using type as map key introduces template substitution errors -


i'm using tuple key track elements in map, , later iterating on map produce string version of map. me conversion, have template convenience function concatenate tuple used key (inspired this answer).

#include <iostream> #include <string> #include <sstream> #include <tuple>  template<std::size_t idx = 0, typename ...t> inline typename std::enable_if<idx == sizeof...(t), void>::type cat_tuple(std::tuple<t...> &t, std::stringstream &s){ }  template<std::size_t idx = 0, typename ...t> inline typename std::enable_if<idx < sizeof...(t), void>::type cat_tuple(std::tuple<t...> &t, std::stringstream &s){     if (idx != 0)         s << ",";     s << std::get<idx>(t);     cat_tuple<idx+1, t...>(t, s); }  typedef std::tuple<int, int> my_tuple; int main(){     my_tuple t(1, 2);     std::stringstream s;     cat_tuple(t, s);     std::cout << s.str() << std::endl; //correctly prints "1,2" } 

i can insert elements map , iterate without error

#include <iostream> #include <string> #include <sstream> #include <tuple> #include <map>  typedef std::tuple<int, int> my_tuple; typedef std::map<my_tuple, int> my_map; int main(){     my_map m;     my_tuple t(1, 2);     m.insert(std::pair<my_tuple, int>(t, 1));     std::stringstream s;     for(my_map::iterator = m.begin(); != m.end(); ++i)         s << i->second;     std::cout << s.str() << std::endl; //correctly prints "1" } 

but when try iterate on map, substitution error:

#include <iostream> #include <string> #include <sstream> #include <tuple> #include <map>  template<std::size_t idx = 0, typename ...t> inline typename std::enable_if<idx == sizeof...(t), void>::type cat_tuple(std::tuple<t...> &t, std::stringstream &s){ }  template<std::size_t idx = 0, typename ...t> inline typename std::enable_if<idx < sizeof...(t), void>::type cat_tuple(std::tuple<t...> &t, std::stringstream &s){     if (idx != 0)         s << ",";     s << std::get<idx>(t);     cat_tuple<idx+1, t...>(t, s); }  typedef std::tuple<int, int> my_tuple; typedef std::map<my_tuple, int> my_map; int main(){     my_map m;     my_tuple t(1, 2);     m.insert(std::pair<my_tuple, int>(t, 1));     std::stringstream s;     for(my_map::iterator = m.begin(); != m.end(); ++i){         if (i != m.begin())             s << "\n";         cat_tuple(i->first, s); //substitution error, see below         s << " " << i->second;     }     std::cout << s.str() << std::endl; } 

producing (g++ 4.2.1 on osx, removed extraneous enable_if notes)

$ g++ asdf.cc -std=c++11 asdf.cc:31:3: error: no matching function call 'cat_tuple'                 cat_tuple(i->first, s); //substitution error, see below                 ^~~~~~~~~ ... asdf.cc:14:1: note: candidate template ignored: substitution failure [with idx =       0, t = <int, int>] cat_tuple(std::tuple<t...> &t, std::stringstream &s){ ^ 1 error generated. 

as says in error message, template want use ignored due substitution failure. difference did introduce when moved map, , how correct it?

change both cat_tuple function templates to

cat_tuple(std::tuple<t...> const& t, std::stringstream &s) //                         ^^^^^ 

this necessary because std::map's keys const.

live demo

in case, cat_tuple's tuple parameter should const& since doesn't modify argument.


you may want rename cat_tuple tuple_printer or similar , change std::stringstream parameter std::ostream, way can pass std::cout if desired output stdout.

also, current name reminiscent of std::tuple_cat.