yehudahs
yehudahs

Reputation: 2668

how to printing generic map in c++

I am tring to write a function to print generic map. this is what I have so far:

    template<typename map_key, typename map_val>
    void log(DEBUG_LEVEL level, std::map<map_key, map_val> _map) {
        if (level >= d_level) {
            for (std::map<map_key, map_val>::iterator it = _map.begin();
                    it != _map.end(); ++it)
                std::cout << it->first << " => " << it->second << '\n';
        }
    }

it doesn't compile.

error: expected ';' before 'it'
error: 'it' was not declared in this scope
  1. why does this isn't compiling ?
  2. is there a better way to write this ? I found a one liner to print a vector here (the second answer)and I wondered if there is the same for a map ?

update: I fix the (1) but still waiting for an answer to (2) I liked Galik answer but when I tried to add it as a function I got an error: error:'std::ostream& Logger::operator<<(std::ostream&, const std::pair<const _Key, _Tp>&)' must take exactly one argument

here is my Logger class:

extern DEBUG_LEVEL d_level;

class Logger {

public:

    Logger(const char * app_name);
    Logger(DEBUG_LEVEL level, char * app_name);
    void log(DEBUG_LEVEL level, const char* str, ...);

    template<typename vector_type>
    void log(DEBUG_LEVEL level, const std::vector<vector_type>& _vec,
            const std::string seperator = ", ") {
        if (level >= d_level) {
            std::cout << get_prefix_msg() << " ";
            change_color(level);
            std::cout << "[";
            std::copy(_vec.begin(), _vec.end(),
                    std::ostream_iterator<vector_type>(std::cout,
                            seperator.c_str()));
            std::cout << "]\n";
            printf(ANSI_COLOR_RESET);
        }
    }

    template<typename map_key, typename map_val>
    void log(DEBUG_LEVEL level, const std::map<map_key, map_val>& _map,
            const std::string seperator = ", ") {
        if (level >= d_level) {
            std::cout << get_prefix_msg() << " \n";
            change_color(level);
            std::cout << "[";
            for (typename std::map<map_key, map_val>::const_iterator it =
                    _map.begin(); it != _map.end(); ++it)
                std::cout << it->first << " => " << it->second << seperator;
            std::cout << "]\n";
            printf(ANSI_COLOR_RESET);
        }
    }

    /**
     * will log but without the application _app_name and without the debug level (but will have the right color)
     */
    void strip_log(DEBUG_LEVEL level, const char* str, ...);

    void change_verbosity(DEBUG_LEVEL level);

    static int msg_id;
private:
    const char * _app_name;
    void change_color(DEBUG_LEVEL level, bool is_strip = false);
    int get_next_msg_id();
    std::string get_prefix_msg();
    static DEBUG_LEVEL d_level;

};

Upvotes: 0

Views: 2206

Answers (2)

Galik
Galik

Reputation: 48605

In answer to your second question, you might consider being even more generic and allowing more different types of containers.

Something like:

#include <map>
#include <set>
#include <vector>
#include <iostream>

typedef int DEBUG_LEVEL;
int d_level = 0;

template<typename Key, typename Value>
std::ostream& operator<<(std::ostream& os, const std::pair<const Key, Value>& p)
{
    os << p.first << " => " << p.second;
    return os;
}

template<typename Container>
void log(DEBUG_LEVEL level, const Container& c) {
    if (level >= d_level) {
        for(typename Container::const_iterator it = c.begin();
            it != c.end(); ++it)
        std::cout << *it << '\n';
    }
}

// OPTIONAL Adding your own types

class MyClass
{
    int i;
    std::string s;
public:
    MyClass(int i, std::string s): i(i), s(s) {}

    // declare the operator<<() overload as a friend to grant access
    // to private members
    friend std::ostream& operator<<(std::ostream& os, const MyClass& mc);

};

// define the operator<<() for MyClass as a global function (required)
std::ostream& operator<<(std::ostream& os, const MyClass& mc)
{
    os << "{MyClass: " << mc.s << ": " << mc.i << "}";
    return os;
}


// End of OPTIONAL

int main()
{
    std::set<int> s;
    s.insert(6);
    s.insert(3);
    s.insert(4);

    std::map<int, int> m;// {{1, 2}, {3, 4}};
    m[1] = 2;
    m[3] = 4;

    std::vector<int> v;
    v.push_back(4);
    v.push_back(3);
    v.push_back(2);
    v.push_back(1);

    std::cout << "\nset:\n";
    log(1, s);

    std::cout << "\nmap:\n";
    log(1, m);

    std::cout << "\nvector:\n";
    log(1, v);

    std::cout << "\nvector of MyClass:\n";
    std::vector<MyClass> vmc;
    vmc.push_back(MyClass(1, "hello"));
    vmc.push_back(MyClass(2, "world"));

    log(1, vmc);
}

Output:

set:
3
4
6

map:
1 => 2
3 => 4

vector:
4
3
2
1

vector of MyClass:
{MyClass: hello: 1}
{MyClass: world: 2}

Upvotes: 4

Jarod42
Jarod42

Reputation: 217135

typename is missing. It should be

template<typename map_key, typename map_val>
void log(DEBUG_LEVEL level, const std::map<map_key, map_val>& _map) {
    if (level >= d_level) {
        for (typename std::map<map_key, map_val>::const_iterator it = _map.begin(); it != _map.end(); ++it)
            std::cout << it->first << " => " << it->second << '\n';
    }
}

or in C++11

template<typename map_key, typename map_val>
void log(DEBUG_LEVEL level, const std::map<map_key, map_val>& _map) {
    if (level >= d_level) {
        for (const auto& p : _map)
            std::cout << p.first << " => " << p.second << '\n';
    }
}

Upvotes: 4

Related Questions