Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should std::reference_wrapper contain the default comparator "<" operator? [closed]

The STL uses the "less than" as the default comparator. An STL comparator call on an object wrapped with the reference_wrapper<> does not compile, even if the underlying class has the "<" operator defined.

It seems, this is because there is no implicit conversion performed on on the LHS of the LHS.operator<(RHS) when it is a member function. I have verified that using a free version as the comparator works.

However, if the reference_wrapper provided the "<" operator, which calls the "<" on the underlying, the need to use the free function will be obviated.

I made the following addition in the code for the reference_wrapper (taken from VS11 Beta xrefwrap.h), and could use std::map with a class wrapped in my version of the reference_wrapper<> which has the "<" operator defined.

    bool operator <(reference_wrapper<_Ty> const rhs) const {
    return this->get() < rhs.get();
}

Added later: If I understand correctly, reference_wrapper<> provides copy/assign semantics associated with ptrs needed by many libraries, while hiding the ptr related syntax. This permits the use of reference type syntax, without the overhead of local copies. To compare it with examples using ptrs completely misses one of the point of the reference_wrappers: you want to avoid the use of ptr type syntax.

The way things stand right now, code which directly works on objects breaks when the objects are wrapped in reference_wrappers. Needless to say, "<" being the default comparator, indeed makes it special; in a significant percentage of existing code, objects will define these to obviate the need for special comparators.

Added Later #2: The history of this feature suggests that avoiding the use of ptr syntax was not the original intent. However, it has been a decade since this was first introduced in boost. With a large number of new programmers "guided" to avoid ptr based syntax (undoubtedly influenced by ptr free languages), this feature can become increasingly useful if it could work more seamlessly, especially when dealing with legacy code storing objects in STL containers, and value copies all over.

Added Later #3: Improving Legacy Code with minimal code changes Over time thin classes become heavy and the size of the objects in the containers increases. A quick way to improve performance is to avoid the copies, via wrapped objects. This will provide the "C ptr" type performance without the extra copies with minimal changes to the code.

std::map<const Object, string> objTable;
// can be rewritten as to avoid object copies using the
// __myOwn::reference_wrapper which contains the '<' operator
std::map<__myOwn::reference_wrapper<const Object>, string> rwTable_myOwn;

// which works with out any non-member free comparator functions
rwTable_myOwn[a]="One"; // Compiles and works

// When using the table with the std::reference_wrapper
std::map<std::reference_wrapper<const Object>, string> rwTable_std;
//the map does not work
rwTable_std[a]="One"; // Fails to compile it needs the custom non-member comparator
like image 810
VSOverFlow Avatar asked May 24 '12 01:05

VSOverFlow


People also ask

What is std :: Reference_wrapper?

std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references.

What is the use of Reference_wrapper?

A reference_wrapper can be used to store references in standard containers, and to pass objects by reference to std::bind . The type Ty must be an object type or a function type, or a static assert fails at compile time. The helper functions std::ref and std::cref can be used to create reference_wrapper objects.


1 Answers

No, it shouldn't. It isn't reference_wrapper's job to do anything but wrap a reference as a value.

If you need to compare two reference_wrapper<T>'s (which is not a reference to T), then it's your job to make that work. For the same reason std::set<T*> doesn't default to defining comparison as std::less<T>(*x, *y), neither should your case. The wrapper is just a non-null pointer.

Why stop at a single comparison operator or all the comparison operators? Why not overload reference wrapper for all of the standard functions? Because it's not worth it when the solution is so easy.

like image 68
GManNickG Avatar answered Oct 12 '22 15:10

GManNickG