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

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?

There's no operator<< for std::variant, which can't be printed out directly. You need to read the value from the variant (by index or type), e.g.
std::cout << std::get<bool>(kwargs["flag"]) << std::endl;
Or
std::cout << std::get<2>(kwargs["flag"]) << std::endl;

You can define operator<< for your type:
std::ostream& operator<<(std::ostream& os, std::variant<float,int,bool,std::string> const& v) {
std::visit([&os](auto const& x) { os << x; }, v);
return os;
}
You can generalize the solution to work with any variant specialization:
template <class Var, class = std::variant_alternative_t<0, Var>>
std::ostream& operator<<(std::ostream& os, Var const& v) {
std::visit([&os](auto const& x) { os << x; }, v);
return os;
}
Note, the second template parameter exists to disable the definition if the Var is not a std::variant specialization.

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

Related

Return type deduction failure in overloaded operator

So I have this class template with a single attribute value of type T where I try to overload the + operator, s.t. adding two objects of this class results in another object of this class where the value is the sum of the values of the two. Here's the code:
template<typename T>
class Number
{
public:
//constructors
Number(T value)
: value(value) {}
//attributes
const T value;
//operators
//addition +
template<typename U>
auto operator+(Number<U> other)
{
auto val = this->value + other.value;
Number output(val); //instantiating object of class Number, using constructor
std::cout << "output value: "<<output.value << std::endl;
std::cout << "auto val: "<< val << std::endl;
return output;
}
};
int main()
{
Number<int> x(2);
Number<float> y(2.5);
Number z=x+y;
std::cout << "x = " << x.value << std::endl;
std::cout << "y = " << y.value << std::endl;
std::cout << "x+y = " << z.value << std::endl;
return 0;
}
.
The output is:
output value:4
auto val: 4.5
x = 2
y = 2.5
x+y = 4
.
Obviously there occurs and undesired type conversion, from float to int and I am trying to find out how to avoid this without resorting to specialization. Explicit declaration of the operator output type does not compile. I understand that here the failure lies in that the auto type output becomes the type Number<T>, which in this case is Number<int> but does it have to be int even when a new object is instantiated within the operator definition scope { }?
I'd appreciate some help in this simple exercise, thank you in advance!
As #NathanPierson mentioned:
Number refers to Number<T> inside the operator. You unfortunately cannot use template argument deduction here.
The return type can be determined based on the type of the additon though. You could use a trailing return type to specify the return type. This assumes you don't need to use the result before returning from the function.
class Number
{
public:
...
template<typename U>
auto operator+(Number<U> other) -> Number<decltype(other.value + value)>
{
return {value + other.value};
}
};
.
You could also implement the operator in namespace scope:
template<class T, class U>
auto operator+(Number<T> const& s1, Number<U> const& s2)
{
auto val = s1.value + s2.value;
Number result(val);
return result;
}

Can't insert non-const value in unordered_map of references

I'm trying to create 2 std::unordered_map, one holds <A, int> and the second one holds <int&, A&>.
I'll explain at the end why I want to do this if you're curious.
My problem is that k_i has value of type std::reference_wrapper, k_i.insert doesn't work. But if I make k_i to have value std::reference_wrapper<const A>, the insert works.
I just can't figure out why is this and I am curious.
<<<<<Edit:
The thing is that find returns std::pair<const Ket, T> as stated by
Eljay in the comments. Because of this, the second std::unordered_map needs to have the value const.
<<<<<
Code:
Compiler: g++ version 10.1
Compile flags: -Wall -Wextra -std=c++20
#include <unordered_map>
#include <iostream>
#include <string>
#include <functional>
class A {
public:
A(const int x) : x(x) {
std::cout << "A::A(const int x) : x(" << x << ")\n";
}
A(const A& a) {
std::cout << "A::A {" << x << "} (const A& a {" << a.x << "} )\n";
x = a.x;
}
A(A&& a) {
std::cout << "A::A {" << x << "} (A&& a {" << a.x << "} )\n";
x = a.x;
}
A& operator=(const A& a) {
std::cout << "A::operator= {" << x << "} (const A& a)\n";
x = a.x;
return *this;
}
A& operator=(A&& a) {
std::cout << "A::operator= {" << x << "} (A&& a)\n";
x = a.x;
return *this;
}
~A() {
std::cout << "A::~A(" << x << ")\n";
}
friend std::ostream& operator<<(std::ostream& os, const A& dt);
int x;
};
std::ostream& operator<<(std::ostream& os, const A& dt) {
return os << dt.x;
}
template <typename K, typename V, typename... args>
void print_um(const std::unordered_map<K, V, args...> &umap) {
for (const auto &[x, y] : umap) {
std::cout << "(" << x << "," << std::ref(y).get() << "); ";
}
std::cout << "\n";
}
template <typename T>
struct MyHash {
std::size_t operator()(T const& s) const noexcept {
return std::hash<int>{}(std::ref(s).get());
}
};
template <typename T>
struct MyEquals {
constexpr bool operator()(const T &lhs, const T &rhs) const {
return lhs == rhs;
}
};
struct MyHash_A {
std::size_t operator()(A const& s) const noexcept {
return std::hash<int>{}(s.x);
}
};
struct MyEquals_A {
constexpr bool operator()(const A &lhs, const A &rhs) const {
return lhs.x == rhs.x;
}
};
int main() {
std::unordered_map<A, int, MyHash_A, MyEquals_A> k_s;
std::unordered_map<std::reference_wrapper<int>, std::reference_wrapper<const A>, MyHash<std::reference_wrapper<int>>, MyEquals<std::reference_wrapper<int>>> k_i;
{
A a(5);
std::cout << "1----\n";
k_s[a] = 12;
std::cout << "2----\n";
}
std::cout << "3----\n";
print_um<>(k_s);
std::cout << "4----\n";
A a(5);
std::cout << "5----\n";
auto it = k_s.find(a);
std::cout << "6----\n";
k_i.emplace((*it).second, (*it).first);
// // k_i[(*it).second] = ref_name;
std::cout << "7----\n";
print_um<>(k_s);
std::cout << "8----\n";
print_um<>(k_i);
std::cout << "9----\n";
int x = 12;
int &ref = x;
auto is_there = k_i.find(ref);
if (is_there != k_i.end()) {
std::cout << "elem: " << (*is_there).second.get() << "\n";
} else {
std::cout << "why? :(\n";
}
std::cout << "10---\n";
return 0;
}
As to why I create this code, I was thinking to be able to access some data by value or by key interchangeably (is there some better data structure? ). Like an username and a token, sometimes I have one, other times I have the other and using references I ensure that I don't waste space. Ofc, if one value has to change, I would invalidate the bucket position in the unordered_map because of the key, but I would treat that problem at a later date. Another motive is to learn some more C++ and test its limits (or mine).
From UnorderedAssociativeContainer requirements:
For std::unordered_map and std::unordered_multimap the value type is std::pair<const Key, T>.
In your code k_s is unordered_map<A, int>, so the value type is pair<const A, int>. In here:
auto it = k_s.find(a);
you get a "pointer" to such pair, and type of (*it).first is const A.
Your k_i is unordered_map<..., ref<A>> and when you do insert here:
k_i.emplace(..., (*it).first);
you essentially attempt to initialize ref<A> with const A, which obviously cannot work.
When you change k_i type to unordered_map<..., ref<const A>>, then you initialize ref<const A> with const A, which is fine.
Many have mentioned in the comment that Key type must be const. However the OP seems to wonder why the value type in k_i also need to be a const.
The reason for that is because you are referencing the key from k_s, which would be const A, and you can not reference it with a non-const reference.
To properly declare k_s, you might want to do something like:
std::unordered_map<
std::reference_wrapper<decltype(k_s)::value_type::second_type>,
std::reference_wrapper<decltype(k_s)::value_type::first_type>,
yourHash, yourComp
> k_s;
One alternative solution for you is to use another container that actually supports bidirectional lookup, such as Boost.Bimap.

Narrowing down a C++ concept to exclude certain types

Suppose I would want to overload the left shift operator for ostreams and all containers.
This is what I'm currently have (compile with -fconcepts):
#include <vector>
#include <iostream>
template<typename Container>
concept bool Iterable = requires(Container t) {
{ *t.begin()++, t.end() };
};
template<Iterable T>
std::ostream& operator<<(std::ostream& out, const T& t) {
for(const auto& it: t) {
out << it << " " ;
}
return out;
}
int main() {
std::vector<int> a = {1, 2, 3};
std::cout << a << std::endl;
std::string str = "something";
// std::cout << str << std::endl; // compile error if the template is defined
return 0;
}
The problem however, is that this there is already a version of the ostream&<< for std::string.
Is there a general (something like a requires not expression) or specific (maybe similar to partial specialization by which I can exclude concrete classes) way to exclude something in a concept?
If not, what is the correct way around this?
template<Iterable T>
requires !requires(std::ostream o, T a) { operator<<(o, a); }
std::ostream& operator<<(std::ostream& out, const T& t) {
for(const auto& it: t) {
out << it << " " ;
}
return out;
}
Add a requirement that the type does not already have an operator<< defined. I am not 100% sure this should work, but it does work on gcc.
(simply o << a crashes gcc)

Overload operator<< for a vector struct of pointer?

I am currently trying to make a overload operator<< to my vector of structs, such that I will print the content of the vector in a matrix format..
this is what I've tried so far
// This file is a "Hello, world!" in C++ language by GCC for wandbox.
#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
struct element
{
std::vector<int> keys;
std::string item;
element(std::vector <int> key, std::string item)
{
keys = key;
this->item = item;
}
};
inline std::stream operator << (std::ostream &stream, const std::vector<element*> _element)
{
for (auto elements: _element)
{
for(auto item : elements)
{
std::stream << item.key << " "
}
}
}
int main()
{
std::cout << "Hello, Wandbox!" << std::endl;
std::vector<element> storage;
std::vector<int> test(10);
std::generate(test.begin(), test.end(), []() {
return rand() % 100;
});
std::string name = "test";
storage.push_back(element(test,name));
std::generate(test.begin(), test.end(), []() {
return rand() % 100;
});
storage.push_back(element(test,name));
std::generate(test.begin(), test.end(), []() {
return rand() % 100;
});
storage.push_back(element(test,name));
std::vector<element*> copy_of_storage;
for(auto elements: storage)
{
copy_of_storage.push_back(&(elements));
}
std::cout << copy_of_storage << std::endl;
}
but for some reason it is not working, and can't seem to understand what is going wrong?
https://wandbox.org/permlink/BQpqmz0HwoXgyS7t
There are a lot of things that are wrong in your operator<<.
First, your return type should be std::ostream& thus you must return stream. In your second loop :
for(auto item : elements)
elements is a pointer of element (the value type of your vector) so you can't iterate other it, you might want to iterate other elements->keys
Here is your fixed function :
inline std::ostream& operator<< (std::ostream &stream, const std::vector<element*> _element)
{
for (auto elements: _element)
for(auto item : elements->keys)
stream << item << " ";
return stream;
}
https://wandbox.org/permlink/qNYVx2yMg7L76NWe
There are quite a few things you can do to fix your code example - better naming conventions would be an important start.
The reason your code doesn't work is because of your operator << function. The following will work:
std::ostream& operator << (std::ostream &stream, std::vector<element*> _elements)
{
for (auto element : _elements)
{
for(auto item : element->keys)
{
stream << item << " ";
}
}
return stream;
}
Your working example: https://wandbox.org/permlink/FVXbLlXEAJpVbfAx
Furthermore:
Refactor your code - better variable names.
Try to use the member initialisation list in the element constructor.
And might be worth changing the ctor params to const &.
operator << should return a std::ostream&.
remove the inline keyword
in the operators << param list, you can remove the const from the std::vector<element*> since it is a copy of a vector that contains non-const pointers.

operator << overloading in a constructor

I'm debugging a program and I would like to make printing from that pattern:
std::cout << firstVar << ", " << secondVar << ", " << thirdVar << endl ;
shorter, i.e, the same thing should happen if we will write the code:
shortPrint(std::cout) << firstVar << secondVar << thirdVar;
note: there is no limit for the variables quantity, it can be 1 and it can be 20, so that should also work:
shortPrint(std::cout) << firstVar << secondVar << thirdVar << anotherVar << oneMoreVar;
Someone told me that the easiest wat to do that is to create class that is called "shortPrint".
Can anyone help me figuring this out?
For start, I would say that I only need to implement a constructor and operator << overloading, but I'm not sure how to do that exactly in that case.
Yes create a shortPrint class with an appropriate overloaded operator. Something like this :
class shortPrint {
ostream &o;
public:
shortPrint(ostream &o) : o(o) {}
template <typename T> shortPrint &operator<<(const T &t) {
o << t << ',';
return *this;
}
// support for endl, which is not a value but a function (stream->stream)
shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
o << pf;
return *this;
}
};
That should work (basically).
To eliminate the problem of extra commas use this :
class shortPrint {
class shortPrint2{
shortPrint &s;
public:
shortPrint2(shortPrint &s) : s(s) {}
template <typename T> shortPrint2 &operator<<(const T &t) {
s.o << ',' << t ;
return *this;
}
shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
s.o << pf;
return s;
}
};
ostream &o;
shortPrint2 s2;
public:
shortPrint(ostream &o) : o(o), s2(*this) {}
template <typename T> shortPrint2 &operator<<(const T &t) {
o << t;
return s2;
}
shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
o << pf;
return *this;
}
};
You can do something like the following:
class _ostream_wrap
{
public:
template <class T>
_ostream_wrap& operator << (const T & v)
{
m_ost << "[ " << v << " ]";
return (*this);
}
explicit _ostream_wrap(std::ostream & ost)
:m_ost(ost)
{}
private:
std::ostream& m_ost;
};
template <class OSTREAM>
_ostream_wrap shortPrint(OSTREAM & o)
{
return _ostream_wrap(o);
}
//...
shortPrint(std::cout) << 1 << 2;
however this implementation will not work on rvalues:
//you can't do something like the following:
shortPrint(MyOstream(some_args)) << 1;
This is because the class _ostream_wrap keeps a reference to the stream and for rvalues case it needs to make a copy. To make a copy you need to have two implementations (this would be the final version):
template <class OSTREAM>
class _ostream_wrap
{
public:
template <class T>
_ostream_wrap<OSTREAM>& operator << (const T & v)
{
m_ost << "[ " << v << " ]";
return (*this);
}
public:
//the constructor is harder to write so i decided
//that for this i will keep the member public
OSTREAM m_ost;
};
template <class OSTREAM>
_ostream_wrap<OSTREAM&> shortPrint(OSTREAM & o)
{
_ostream_wrap<OSTREAM&> rvalue;
rvalue.m_ost = o;
return rvalue;
}
template <class OSTREAM>
_ostream_wrap<OSTREAM> shortPrint(const OSTREAM & o)
{
_ostream_wrap<OSTREAM> rvalue;
rvalue.m_ost = o;
return rvalue;
}
Here's something with very basic functionality:
#include <iostream>
struct shortPrint {
explicit shortPrint(std::ostream& os)
: strm(&os), first(true) {}
template<typename T>
shortPrint& operator<<(T&& t)
{
if (first) {
first = false;
} else {
*strm << ", ";
}
*strm << std::forward<T>(t);
return *this;
}
shortPrint& operator<<( std::ostream& (*func)(std::ostream&) )
{
*strm << func;
return *this;
}
private:
std::ostream* strm;
bool first;
};
int main()
{
int i = 3;
shortPrint(std::cout) << "1" << 2 << i << std::endl;
shortPrint(std::cout) << 4;
}
The tricky part is getting the commas to be printed correctly. I chose to print them before every streamed object, except before the very first one. As you can see, there's one general operator<< template that simply prints the comma and forwards the argument. The next problem are stream manipulators, because we don't want to print commas before them. The other operator<< overload takes care of that. If you want to be more generic, there's two more you need to take care of (see no. 9 here ).
Hope that helps.
Return the ostream from the function. Something like:
std::ostream &shortPrint(std::ostream &out) {
//whatever you need here
return out;
}
Edit: you the kind of formatting you need, you need to make a class with overloaded stream operator that returns the class. But you need to keep the reference to the needed stream in the class.