Reputation: 15641
I mean to write a generic overload of operator<<
to print STL containers.
I put together code below.
Whenever operator<<
involves a string
, it produces a compilation error ambiguous overload for 'operator<<'
, in the example in problem lines 1 and 2.
How can I get rid of the error, without losing the generic overload, and without having to write explicit instantiations for every possible use of containers with strings? Perhaps excluding from my overload the strings.
#include <iostream>
#include <vector>
#include <set>
#include <list>
#include <map>
#include <tuple>
#include <string>
// Maximum number of printed values. After this, print "..."
#define MAX_PRINT_VALS 10
//=========================================================================
// Set of functions to dump STL containers
template <template <class...> class Container, class ...T>
std::ostream& operator<<(std::ostream& os, const Container<T...>& c)
{
os << "[";
size_t nvals = 0;
for ( auto iter = c.begin() ; iter != c.end() ; iter++ ) {
os << *iter;
nvals++;
if (iter != --c.end())
os << ", ";
if (nvals > MAX_PRINT_VALS) {
os << "... (total of " << c.size() << " values)";
break;
}
}
os << "]";
return os;
}
template<class Key, class T>
std::ostream& operator<<(std::ostream& os, const std::pair<Key, T>& p)
{
os << "(" << p.first << ", " << p.second << ")";
//os << std::endl;
return os;
}
using namespace std;
int main(int argc, char **argv) {
//============================================================
// Print vector
const size_t nmax = 3;
vector<double const*> vec_dp;
for (size_t n = 0; n < nmax; n++) {
vec_dp.push_back(new double(n+1.5));
}
cout << "Vector of indices vec_dp = " << vec_dp << endl;
for (size_t n = 0; n < nmax; n++) {
delete vec_dp[n];
}
vector<string> vec_s;
for (size_t n = 0; n < nmax; n++) {
vec_s.push_back("asa");
}
cout << "Vector of string vec_s = " << vec_s << endl; // PROBLEM LINE 1
//============================================================
// Print set
set<double> set_d;
for (size_t n = 0; n < nmax; n++) {
set_d.insert(n+1.3);
}
cout << "Set of double set_d = " << set_d << endl;
//============================================================
// Print list
list<double> list_d;
for (size_t n = 0; n < (nmax + 10); n++) {
list_d.emplace_back(n+1.4);
}
cout << "List of double list_d = " << list_d << endl;
//============================================================
// Print map
typedef pair<int, int> pair2_t;
map<pair2_t::first_type, pair2_t::second_type> map_i_i;
for (size_t n = 0; n < (nmax + 10); n++) {
map_i_i.insert(pair2_t(n+1, n+2));
}
cout << "Map of (int, int) map_i_i = " << map_i_i << endl;
typedef pair<int, string> pair1_t;
map<pair1_t::first_type, pair1_t::second_type> map_i_s;
for (size_t n = 0; n < (nmax + 10); n++) {
map_i_s.insert(pair1_t(n+1, "one"));
}
cout << "Map of (int, string) map_i_s = " << map_i_s << endl; // PROBLEM LINE 2
return 0;
}
Related
Upvotes: 1
Views: 160
Reputation: 1
How can I get rid of the error, without losing the generic overload, and without having to write explicit instantiations for every possible use of containers with strings? Perhaps excluding from my overload the strings
You can use std::enable_if
(since you're using c++17) to exclude your own overload for std::string
as shown below:
template <template <class... K> class Container, class ...T >
//added this to make use of SFINAE
std::enable_if_t<not (std::is_same_v<std::string, Container<T...>>),std::ostream&> operator<<(std::ostream& os, const Container<T...>& c)
{
//other code as before...
os << "]";
return os;
}
//other code as before...
int main(int argc, char **argv) {
//other code as before...
cout << "Vector of string vec_s = " << vec_s << endl; //works now
}
With c++20 you could instead make use of requires
and perhaps can make the code more readable. Demo
Upvotes: 3