Search code examples
c++dictionaryvariant

How can I print map key/value with std::variant?


I'm trying to print the key of a certain value in my dictionary. I defined my map like this:

std::map<std::string, std::variant<float,int,bool,std::string>> kwargs; 
kwargs["interface"] = "probe"; 
kwargs["flag"] = true; 
kwargs["Height"] = 5; 
kwargs["length"] = 6; 

I tried to print the value normally but a (no operator "<<" matches these operands) error occurs.

std::cout << kwargs["flag"] << std::endl; 

Can someone help me with this error?


Solution

  • I would use std::visit with a generic lambda that prints any type to std::cout, as follows:

    std::map<std::string, std::variant<float,int,bool,std::string>> kwargs; 
    kwargs["interface"] = "probe"s;
    kwargs["flag"] = true; 
    kwargs["Height"] = 5; 
    kwargs["length"] = 6; 
    
    for (const auto& [k, v] : kwargs){
        std::cout << k << " : ";
        std::visit([](const auto& x){ std::cout << x; }, v);
        std::cout << '\n';
    }
    

    This works because all of float, int, bool, and std::string have overloads for the output stream operator <<. For other types, or to override this behaviour, you could use a custom functor class instead of a lambda:

    struct PrintVisitor {
        template<typename T>
        void operator()(const T& t) const {
            std::cout << t;
        }
    
        // prints std::string in quotes
        void operator(const std::string& s) const {
            std::cout << '\"' << s << '\"';
        }
    };
    
    [...]
    
    std::visit(PrintVisitor{}, kwargs);
    

    NOTE: unfortunately, the line kwargs["interface"] = "probe"; doesn't actually select the std::string constructor for the variant type, because the string literal preferentially converts to a bool rather than a std::string (further reading). You can avoid this by explicitly making a std::string using, for example, std::string{"probe"} or the standard std::string user-defined literal, as in "probe"s.

    Live demo