Is unordered_set<reference_wrapper<Ty>> valid? - c++

Is this valid C++ (considering the latest standard)? I'm getting compilation errors with near-top-of-tree clang/libc++ on Ubuntu 12.04. If it should be valid, I'll mail the clang-dev list with error messages and such.
#include <functional>
#include <unordered_set>
struct X
{
int i;
};
void f ()
{
std::unordered_set<std::reference_wrapper<X>> setOfReferencesToX;
// Do stuff with setOfReferencesToX
}
** As an aside, I'm tired of qualifying that the question/answer is specific to the latest standard. Could the C++ community as a whole, please start qualifying things that are specific to the old standard instead? The newer standard has been out for about a year now.

The problem is not specific to std::reference_wrapper<T>, but rather to the type X itself.
The issue is that std::unordered_set requires that you define hashing and equality functors for std::reference_wrapper<X>. You can pass the hash functor as second template parameter.
For example, this would work:
#include <functional> // for std::hash<int>
struct HashX {
size_t operator()(const X& x) const {
return std::hash<int>()(x.i);
}
};
and then
std::unordered_set<std::reference_wrapper<X>, HashX> setOfReferencesToX;
Another option is to make a specialization for std::hash<X>:
namespace std {
template <>
struct hash<X> {
size_t operator()(const X& x) const {
return std::hash<int>()(x.i);
}
};
}
This allows you to avoid explicitly specifying the 2nd template argument:
std::unordered_set<std::reference_wrapper<X>> setOfReferencesToX;
Concerning the equality comparison, you can fix this by providing an equality operator for class X:
struct X
{
bool operator==(const X& rhs) const { return i == rhs.i; }
int i;
};
Otherwise, you can define your own functor and pass it as third template argument.

Related

Generic comparison operator for structs

In many of my unit tests I need to compare the contents of simple structs having only data members:
struct Object {
int start;
int stop;
std::string message;
}
Now, if I want to write something like:
CHECK(object1==object2);
I always have to implement:
bool operator==(const Object& lhs, const Object& rhs) {
return lhs.start==rhs.start && lhs.stop==rhs.stop && lhs.message=rhs.message;
}
Writing all these comparison functions becomes tedious, but is also prone to errors. Just imagine, what will happen if I add a new data member to Object, but the comparison operator will not be updated.
Then I remembered my knowledge in Haskell and the magic deriving(Eq) directive, which just generates a sane comparison function for free.
How, could I derive something similar in C++?
Happily, I figured out that C++17 comes with a generic operator== and that every struct should be easily convertible to an std::tuple by the virtue of std::make_tuple.
So I boldly tried the following:
#include <tuple>
#include <iostream>
#include <tuple>
template<typename T>
bool operator==(const T& lhs, const T& rhs)
{
auto leftTuple = std::make_tuple(lhs);
auto rightTuple = std::make_tuple(rhs);
return leftTuple==rightTuple;
}
struct Object
{
std::string s;
int i;
double d;
};
int main(int arg, char** args)
{
std::cout << (Object{ "H",1,2. } == Object{ "H",1,2. }) << std::endl;
std::cout << (Object{ "A",2,3. } == Object{ "H",1,2. }) << std::endl;
return EXIT_SUCCESS;
}
But, unfortunately it just doesn't compile and I really don't know why. Clang tells me:
main.cpp:11:18: error: use of overloaded operator '==' is ambiguous (with operand types
'std::tuple<Object>' and 'std::tuple<Object>')
return leftTuple==rightTuple;
Can I possibly fix this compile error to get my desired behavior?
No, since comparing tuples reverts to comparing the elements of the tuple, so leftTuple == rightTuple tries to compare two Objects which is not possible.
that every struct should be easily convertible to an std::tuple by the virtue of std::make_tuple
No, you'll just get a tuple with one element, the struct.
The trick is to use std::tie:
std::tie(lhs.mem1, lhs.mem2) == std::tie(rhs.mem1, rhs.mem2)
but that has the same problem as your original solution. Unfortunately C++17 doesn't have any facility to avoid this problemyou could write a macro :). But in C++20 you will be able to do:
struct Object
{
std::string s;
int i;
double d;
bool operator==(const Object &) const = default;
};
which will generate the correct comparison operators for Object.

Use std::variant as class member and apply visitor

I'm trying to use std::variant as a class member variable and then use operator overloading so that the two Variants of this class can use the operator plus to produce a new variable. The problem is that std::get does not work as I thought and so I cannot retrieve the correct (hardcoded) string types so that the AddVisitor struct is used.
I get a compilation error that says: no matching function for call to ‘get<0>(std::basic_string&)’
Also is there a way that operator+ function detects the type without if-else statements?
I have already checked a lot of answers in SO including ones that answer questions about similar Boost functionality, but I cannot get it to work.
#include <iostream>
#include <variant>
#include <string>
#include "stdafx.h"
using Variant = std::variant<int, std::string>;
template<typename T>
struct AddVisitor
{
T operator()(T v1, T v2)
{
return v1 + v2;
}
};
class Var
{
Variant v;
public:
template<typename T>
Var(T value) : v(value) {}
Var operator+(Var& val)
{
// PROBLEM: This is a hard coded example that I want to use, so that concatenation of two strings happens.
return std::visit(AddVisitor<std::string>(), std::get<std::string>(v), std::get<std::string>(val.get()));
// Is there a way to get the correct type without if-else statements here?
}
Variant get()
{
return v;
}
};
int main()
{
Var x("Hello "), y("World");
// The expected output is this:
Var res = x + y;
return 0;
}
I expect to be able to use the plus operator and concatenate two strings or two integers and create a new Var variable.
Ok, so there are a few things to talk about.
First, the visitor for std::visit with more than one variant argument should accept all combinations of variant types. In your case it should accept:
(string, string)
(string, int)
(int, int)
(int, string)
If for you only string, string and int, int are valid you still need to accept the other combinations for the code to compile, but you can throw in them.
Next, the visitor shouldn't be templated. Instead the operator() should be templated or overloaded for all the above combinations.
So here is AddVisitor:
struct AddVisitor
{
auto operator()(const std::string& a, const std::string& b) const -> Variant
{
return a + b;
}
auto operator()(int a, int b) const -> Variant
{
return a + b;
}
// all other overloads invalid
template <class T, class U>
auto operator()(T, U) const -> Variant
{
throw std::invalid_argument{"invalid"};
}
};
It's not clear from documentation what the overloads can return, but I couldn't make it compile unless all return Variant. Fortunately the compiler errors are TREMENDOUSLY HELPFULL . (I need to check the standard).
Next, when you call std::visit you need to pass the variants you have.
So the final code is this:
auto operator+(Var& val) -> Var
{
return std::visit(AddVisitor{}, get(), val.get());
}
And you can indeed use it like you want:
Var res = x + y;
Another issue with your code is that get makes unnecessary copies. And copies of std::variant are not cheap to make. So I suggest:
auto get() const -> const Variant& { return v; }
auto get() -> Variant& { return v; }

how to trivially adapt set or map ordering predicate for pointers

There must be a trivial answer to this...
I have a std::set or a std::map or some object type which has a natural ordering - say std::less.
I need to change my set or map to contain shared_ptr instead of copies of T.
So I want something like:
using my_set std::set<std::shared_ptr<T>, std::less<*T>>;
But I'm drawing a blank as to how to specify "use the less adaptor on ____ adaptor of T so that it's on dereferenced members, not on shared_ptrs!"
Is there a std::less<std::dereference<std::shared_ptr<T>>> equivalent?
There is currently no functor in the C++ standard library to achieve what you want. You can either write a custom comparator, or if you need this functionality often, come up with an indirect/dereference function object.
Related and potentially helpful threads; the first one offers a generic solution for many operators (even if it requires a bit of code):
Why do several of the standard operators not have standard functors?
Functor that calls a function after dereferencing?
Less-than function dereferencing pointers
While the standard library may not already provide what you need, I think it's pretty trivial to write your own std::dereference_less:
#include <memory>
#include <set>
namespace std
{
template<typename T>
struct dereference_less
{
constexpr bool operator ()(const T& _lhs, const T& _rhs) const
{
return *_lhs < *_rhs;
}
};
}
int main()
{
using key_type = std::shared_ptr<int>;
std::set<key_type, std::dereference_less<key_type>> mySet;
}
Demo (refactored a bit to have a template type alias like in your question)
Since you are already changing your internal interface to something that requires dereferencing you could also just write a wrapper class and provide a bool operator< () as follows:
#include <memory> // shared_ptr
#include <set> // set
#include <iostream> // cout
using namespace std;
template<typename T>
class wrapper
{
public:
shared_ptr<T> sp;
bool operator< (const wrapper<T>& rhs) const
{
return *( sp.get() ) < *( rhs.sp.get() ) ;
}
wrapper(){}
wrapper(shared_ptr<T> sp):sp(sp){}
};
int main()
{
shared_ptr<int> sp1 (new int);
*sp1 = 1;
shared_ptr<int> sp2 (new int);
*sp2 = 2;
set<wrapper<int>> S;
S.insert(wrapper<int>(sp2));
S.insert(wrapper<int>(sp1));
for (auto& j : S)
cout << *(j.sp) << endl;
return 0;
}

Generate attribute members into string automatically from C++ class?

I am programming in C++ (still a beginner), and I was wondering a question about generating automatically value members of class into string for example :
class Point
{
private:
int x;
int y;
public:
std::list<std::string> getValues();
}
In my opinion, I think I must code the function getValues, transform the ints into strings and put the string in a list and return the list, but my tutor asks me if there is a way to do this function automatically,without writting the code, and I don't know how to answer.
Because if we add a new member value (ex : int z), we will have to recode the function getValues().Apparently there is some way to do this in Java,but I was wondering if there is similar way into C++.
Best regards
It is difficult to say what your tutor really wanted from you, but if I were your tutor I would love you to learn about Boost.Fusion Adapted Structures and techniques it is based on (in particular typemaps).
Example with Boost.Fusion:
#include <boost/fusion/adapted/struct/define_struct.hpp>
#include <boost/fusion/algorithm/iteration/fold.hpp>
#include <boost/lexical_cast.hpp>
#include <iterator>
#include <list>
#include <string>
#include <iostream>
BOOST_FUSION_DEFINE_STRUCT(
(), Point,
(int, x)
(long, y)
(double, z)
)
template <class Itr> struct collector_t
{
using result_type = Itr;
template <class T>
Itr operator()(Itr itr, T const& val) const { *itr = boost::lexical_cast<std::string>(val); return ++itr; }
};
int main()
{
Point p {123, 456l, 123.456};
// create and populate the resulting list using boost.fusion facilities
std::list<std::string> strings;
auto sink = std::back_inserter(strings);
boost::fusion::fold(p, sink, collector_t<decltype(sink)>());
// dump the resulting list to prove the example
for (auto s: strings) std::cout << s << '\n';
return 0;
}
There is no way to do this automatically in C++. That would require reflection, i.e., code must be able to reason about the fields a class has. This is not possible in C++. It is possible in Java, so you are right, one can do this automatically in Java.
In a non-automated way: using visitation (compile-time).
class Point {
public:
//
// With visitation (names are optional)
//
template <typename Visitor>
void visit(Visitor&& visitor) {
visitor("x", x);
visitor("y", y);
}
template <typename Visitor>
void visit(Visitor&& visitor) const {
visitor("x", x);
visitor("y", y);
}
//
// With tuples
//
auto as_tuple() -> std::tuple<int&, int&> {
return std::tie(x, y);
}
auto as_tuple() const -> std::tuple<int const&, int const&> {
return std::tie(x, y);
}
private:
int x;
int y;
};
Yes, those solutions require some more maintenance. However all the code is exposed without the need to mentally expand a macro. As a result, potential compilation error messages tend to be clearer and understanding is eased.
As for the maintenance burden ?
you can automate (unit-test) the correlation of the two methods (make sure they both return the same number of members in the same order)
automating detection of incomplete methods is slightly harder, but if a member is missing and tested it will show up too
Note: I personally prefer the as_tuple version, it makes writing == and < so easy.
Note: detection of incomplete methods (missing members) can be attempted using sizeof and the ABI rules.
The question really has two parts:
Finding all members and
Converting them to string.
Finding members is not possible in pure C++, because it does not have any form of reflection. You could resort to special declaration macros using the standard preprocessor like Boost.Fusion does or you can use your own preprocessor like OpenC++ or using the Clang front-end.
For converting to strings, the standard approach would then be like this:
template <typename T>
std::string to_string(T const &v) {
std::stringstream s;
s << v;
return s.str();
}
You can avoid typing this in and use Boost.Lexical Cast.
Note that C++11 also has std::to_string, but it is only defined for numeric types and therefore not very useful for this purpose.

Overloaded [] operator on template class in C++ with const / nonconst versions

Whew, that was a long title.
Here's my problem. I've got a template class in C++ and I'm overloading the [] operator. I have both a const and a non-const version, with the non-const version returning by reference so that items in the class can be changed as so:
myobject[1] = myvalue;
This all works until I use a boolean as the template parameter. Here's a full example that shows the error:
#include <string>
#include <vector>
using namespace std;
template <class T>
class MyClass
{
private:
vector<T> _items;
public:
void add(T item)
{
_items.push_back(item);
}
const T operator[](int idx) const
{
return _items[idx];
}
T& operator[](int idx)
{
return _items[idx];
}
};
int main(int argc, char** argv)
{
MyClass<string> Test1; // Works
Test1.add("hi");
Test1.add("how are");
Test1[1] = "you?";
MyClass<int> Test2; // Also works
Test2.add(1);
Test2.add(2);
Test2[1] = 3;
MyClass<bool> Test3; // Works up until...
Test3.add(true);
Test3.add(true);
Test3[1] = false; // ...this point. :(
return 0;
}
The error is a compiler error and the message is:
error: invalid initialization of non-const reference of type ‘bool&’ from a temporary of type ‘std::_Bit_reference’
I've read up and found that STL uses some temporary data types, but I don't understand why it works with everything except a bool.
Any help on this would be appreciated.
Because vector<bool> is specialized in STL, and does not actually meet the requirements of a standard container.
Herb Sutter talks about it more in a GOTW article: http://www.gotw.ca/gotw/050.htm
A vector<bool> is not a real container. Your code is effectively trying to return a reference to a single bit, which is not allowed. If you change your container to a deque, I believe you'll get the behavior you expect.
A vector<bool> is not implemented like all other vectors, and does not work like them either. You are better off simply not using it, and not worrying if your code can't handle its many peculiarities - it is mostly considered to be A Bad Thing, foisted on us by some unthinking C++ Standard committee members.
Some monor changes to your class should fix it.
template <class T>
class MyClass
{
private:
vector<T> _items;
public:
// This works better if you pass by const reference.
// This allows the compiler to form temorary objects and pass them to the method.
void add(T const& item)
{
_items.push_back(item);
}
// For the const version of operator[] you were returning by value.
// Normally I would have returned by const ref.
// In normal situations the result of operator[] is T& or T const&
// But in the case of vector<bool> it is special
// (because apparently we want to pack a bool vector)
// But technically the return type from vector is `reference` (not T&)
// so it you use that it should compensate for the odd behavior of vector<bool>
// Of course const version is `const_reference`
typename vector<T>::const_reference operator[](int idx) const
{
return _items[idx];
}
typename vector<T>::reference operator[](int idx)
{
return _items[idx];
}
};
As the other answers point out, a specialization is provided to optimize for space allocation in the case of vector< bool>.
However you can still make your code valid if you make use of vector::reference instead of T&. In fact it is a good practice to use container::reference when referencing data held by a STL container.
T& operator[](int idx)
becomes
typename vector<T>::reference operator[](int idx)
Of course ther is also a typedef for const reference:
const T operator[](int idx) const
and this one becomes (removing the useless extra copy)
typename vector<T>::const_reference operator[](int idx) const
The reason for the error is that vector<bool> is specialized to pack the boolean values stored within and vector<bool>::operator[] returns some sort of proxy that lets you access the value.
I don't think a solution would be to return the same type as vector<bool>::operator[] because then you'd be just copying over the regrettable special behavior to your container.
If you want to keep using vector as the underlying type, I believe the bool problem could be patched up by using a vector<MyBool> instead when MyClass is instantiated with bool.
It might look like this:
#include <string>
#include <vector>
using namespace std;
namespace detail
{
struct FixForBool
{
bool value;
FixForBool(bool b): value(b) {}
operator bool&() { return value; }
operator const bool& () const { return value; }
};
template <class T>
struct FixForValueTypeSelection
{
typedef T type;
};
template <>
struct FixForValueTypeSelection<bool>
{
typedef FixForBool type;
};
}
template <class T>
class MyClass
{
private:
vector<typename detail::FixForValueTypeSelection<T>::type> _items;
public:
void add(T item)
{
_items.push_back(item);
}
const T operator[](int idx) const
{
return _items[idx];
}
T& operator[](int idx)
{
return _items[idx];
}
};
int main(int argc, char** argv)
{
MyClass<string> Test1; // Works
Test1.add("hi");
Test1.add("how are");
Test1[1] = "you?";
MyClass<int> Test2; // Also works
Test2.add(1);
Test2.add(2);
Test2[1] = 3;
MyClass<bool> Test3; // Works up until...
Test3.add(true);
Test3.add(true);
Test3[1] = false; // ...this point. :(
return 0;
}