I am trying to refactor some code that doesn't use the STL to use the generic algorithms it provide.
I have a struct like this :
struct A {
int i;
//other stuff...
};
// ...
A* array; // array of A objects, sorted by A::i member
int n = ...; // array size
there is then a function that was coded that takes A, n and an integer k, whose purpose is to give me pointers to to the first and the last element of the array that have their i member equal to k.
This is implemented by hand in terms of binary search. I was thinking about using std::equal_range. The problem is that it requires an object of type A to work, and it forces me to introduce a "dummy" A object with it's i member equal to k.
Is there a way to do this using the STL, without having to introduce a "dummy" object?
thanks
Provided your range is sorted according to the value of A::i, this is trivially done with a custom comparator, but note that the comparator must be able compare both ways:
struct AComp
{
bool operator()(int n, A const & a) const { return n < a.i; }
bool operator()(A const & a, int n) const { return a.i < n; }
};
auto p = std::equal_range(array, array + n, 5, AComp());
Now the range [p.first, p.second) contains the elements with A::i equal to 5.
The linked page contains more or less exactly this example.
You may also use std::binary_search() defined in <algorithm> for binary search generally. The prorotype is:
template <class ForwardIterator, class T>
bool binary_search (ForwardIterator first, ForwardIterator last,
const T& val);
or:
template <class ForwardIterator, class T, class Compare>
bool binary_search (ForwardIterator first, ForwardIterator last,
const T& val, Compare comp);
You can define a conversion operator(This is more like a hack, I guess)
class A
{
private:
int i;
public:
A(int x) : i(x){}
operator int(){
return i;
}
};
If this is done you dont have to define operator< in your struct.
Related
How would you elegantly (and in a modern C++ way) write a function that returns the index of a vector element, taking as argument this vector, and a reference to one of its elements ?
Exceptions handling would be appreciated.
#include <vector>
template <class T>
std::size_t GetIndexFromRef(std::vector<T> &vec, T &item)
{
...
};
This does the trick:
template <class T>
std::size_t GetIndexFromRef(std::vector<T> const &vec, T const &item)
{
T const *data = vec.data();
if(std::less<T const *>{}(&item, data) || std::greater_equal<T const *>{}(&item, data + vec.size()))
throw std::out_of_range{"The given object is not part of the vector."};
return static_cast<std::size_t>(&item - vec.data());
};
I'm using std::less and std::greater_equal, because ([comparisons.general§2]):
For templates less, greater, less_equal, and greater_equal, the specializations for any pointer type yield a result consistent with the implementation-defined strict total order over pointers ([defns.order.ptr]).
[Note 1: If a < b is well-defined for pointers a and b of type P, then (a < b) == less<P>()(a, b), (a > b) == greater<P>()(a, b), and so forth.
— end note]
Otherwise, performing the comparison with an object that isn't part of the vector would be UB.
I have the following situation. Let say we want to implement a sorted array data structure which keeps the array sorted upon insertion. At first attempt, I would do something like:
template<typename T, typename Comparator, Comparator comparator>
SortedArray {
public:
void find(T value);
void insert(T value);
void remove(T value);
}
The argument T is of course for the type of the elements in the array. Then I need a comparator to tell how to compare objects of type T so that I can keep the elements sorted. Since I want to allow for both function pointers (as in classical qsort) as well as function objects and maybe lambda as well, I need to add the template parameter for the comparator.
Now the problem is that I want the compiler to automatically deduce the 2nd Comparator argument based on the 3rd argument. Right now, a typical usage will be exploiting decltype like
int compare_int(int x, int y) {
return x - y;
}
SortedArray<int, decltype(compare_int), compare_int> myArray;
but this doesn't work with lambda and certainly I would love to just write
SortedArray<int, compare_int> myArray;
instead.
Any idea or is it actually possible in C++ at the moment?
You can non type template parameters as follows:
template<typename T, auto C >
class SortedArray
{
private:
std::vector<T> v;
public:
void sort(){ std::sort( v.begin(), v.end(), C );}
void print() { for( auto& el: v ) std::cout << el << std::endl; }
void push(T t){ v.push_back(t);}
};
bool compare_int( int a, int b )
{
return a<b;
}
int main()
{
SortedArray<int, compare_int> sa1;
sa1.push(5);
sa1.push(3);
sa1.push(7);
sa1.sort();
sa1.print();
SortedArray<int, [](int a, int b){ return a<b;} > sa2;
sa2.push(5);
sa2.push(3);
sa2.push(7);
sa2.sort();
sa2.print();
}
As you can see, you can also use a lambda as template parameter.
There is no need to do any template gymnastic with derived template parameters anymore.
Consider a function that accepts one or more parameters (e.g. file names). In order to make it versatile, it is advantageous to write it for a general iterator range:
template<class Iter>
void function(Iter first, Iter last)
{
// do something
}
Now we can invoke it in the following way, independently of how we store the arguments:
WhateverContainer container;
function(std::begin(container), std::end(container));
For example, the STL relies heavily on this paradigm.
Now, imagine we want to invoke the function with a single argument that is not stored in a container. Of course we can write:
const int value = 5;
std::vector<int> vec(1, value);
function(std::begin(vec), std::end(vec));
But this solution seems clumsy and wasteful to me.
Question: Is there a better low-overhead way of creating an iterator-range-compatible representation of a single variable?
You can use pointers, for once:
function(&value, &value + 1);
In generic code, std::addressof instead of the unary operator & is somewhat safer, depending on your level of paranoia.
You can of course wrap this in an overload for easier use:
template <class T>
decltype(auto) function (T &&e) {
auto p = std::addressof(e);
return function(p, p + 1);
}
You can treat it like an array of one element per [expr.unary.op]/3:
function(&value, &value + 1);
For purposes of pointer arithmetic ([expr.add]) and comparison ([expr.rel], [expr.eq]), an object that is not an array element whose address is taken in this way is considered to belong to an array with one element of type T.
You can also overload your function template function for a single-element range:
template<typename Iter>
void function(Iter first) {
return function(first, std::next(first)); // calls your original function
}
This way, your original function function remains compatible with iterator ranges. Note, however, that using this overload with an empty range will result in undefined behavior.
For a single element, value, you can use the overload above:
function(&value); // calls overload
Since operator & may be overloaded, consider also using std::addressof instead of &, as already mentioned in this answer.
For a range consisting of a single element, you can use the overload above as well, which only needs a single iterator instead of an iterator pair:
const int value = 5;
std::vector<int> vec(1, value); // single-element collection
function(std::begin(vec)); // <-- calls overload
I think I'd do this in two steps:
Define a overload of the template function that takes a container, written in terms of the iterator version.
Define a proxy class which treats an object reference as an array of size 1.
c++17 example:
#include <iterator>
#include <type_traits>
#include <vector>
#include <iostream>
// proxy object
template<class T>
struct object_as_container
{
using value_type = T;
using iterator = T*;
using const_iterator = std::add_const_t<T>;
object_as_container(value_type& val) : object_(val) {}
const_iterator begin() const { return std::addressof(object_); }
iterator begin() { return std::addressof(object_); }
const_iterator end() const { return std::next(begin()); }
iterator end() { return std::next(begin()); }
private:
value_type& object_;
};
// our function in terms of iterators
template<class Iter> void func(Iter first, Iter last)
{
while(first != last)
{
std::cout << *first++;
}
}
// our function in terms of containers
template<class Container> void func(Container&& cont)
{
func(cont.begin(), cont.end());
}
int main()
{
const int value = 5;
func(object_as_container(value));
func(std::vector { 1,2,3,4,5 });
}
C++14 introduces Compare::is_transparent for equivalent find operations in associative containers.
template< class K > iterator find( const K& x );
template< class K > const_iterator find( const K& x ) const;
Finds an element with key that compares equivalent to the value x.
This overload only participates in overload resolution if the
qualified-id Compare::is_transparent is valid and denotes a type. It
allows calling this function without constructing an instance of Key
Since there is no longer temporary instance of Key constructed, these can be more efficient.
There does not seem to be an equivalent for unordered containers.
Why is there no Compare::key_equal / Compare::hash_equal?
I imagine it would be relatively simple to allow efficiently looking up of, eg, string literals in unordered containers?
template<>
struct hash<string>
{
std::size_t operator()(const string& s) const
{
return ...;
}
// hash_equal=true allows hashing string literals
std::size_t operator()(const char* s) const
{
return ...;
}
};
Keys that compare equal should produce the same hash value. Decoupling the hash function and the predicate, and at the same time making one or both heterogeneous, could be too much error prone.
Recent paper, P0919r2, brings up the following example:
std::hash<long>{}(-1L) == 18446744073709551615ULL
std::hash<double>{}(-1.0) == 11078049357879903929ULL
Although -1L and -1.0 compare equal, some heterogeneous hash function, not in line with the selected equality comparison logic, could produce different values. The paper adds heterogeneous lookup-enabled function templates --
find, count, equal_range, and contains -- but makes them available when the below requirements are met [unord.req]/p17:
If the qualified-id Hash::transparent_key_equal is valid and denotes a type ([temp.deduct]), then the program is ill-formed if either:
qualified-id Hash::transparent_key_equal::is_transparent is not valid or does not denote a type, or
Pred is a different type than equal_to<Key> or Hash::transparent_key_equal.
The member function templates find, count, equal_range, and contains shall not participate in overload resolution unless the qualified-id Hash::transparent_key_equal is valid and denotes a type ([temp.deduct]).
In such a case, Hash::transparent_key_equal overwrites the default predicate (std::equal_to<Key>) and is used for (transparent) equality checking, together with Hash itself for (transparent) hashing.
Under these conditions, the below transparent function objects could be used to enable heterogeneous lookup:
struct string_equal
{
using is_transparent = void;
bool operator()(const std::string& l, const std::string& r) const
{
return l.compare(r) == 0;
}
bool operator()(const std::string& l, const char* r) const
{
return l.compare(r) == 0;
}
bool operator()(const char* l, const std::string& r) const
{
return r.compare(l) == 0;
}
};
struct string_hash
{
using transparent_key_equal = string_equal; // or std::equal_to<>
std::size_t operator()(const std::string& s) const
{
return s.size();
}
std::size_t operator()(const char* s) const
{
return std::strlen(s);
}
};
Both -- string_equal and std::equal_to<> -- are transparent comparators and can be used as transparent_key_equal for string_hash.
Having this type alias (or a type definition itself) within the hash function class definition makes it clear that it is a valid predicate that works fine with that particular hashing logic and the two can't diverge. Such an unordered set can be declared as:
std::unordered_set<std::string, string_hash> u;
or:
std::unordered_set<std::string, string_hash, string_hash::transparent_key_equal> u;
Either will use string_hash and string_equal.
If you watch the Grill the committee video from CppCon, they explain why stuff like this happens: nobody fought for it.
C++ is standardized by committee but that committee requires input from the community. Someone has to write papers, respond to criticism, go to the meetings, etc... Then the feature can be voted on. The committee doesn't just sit there inventing language and library features. It only discusses and votes on those that are brought forward to it.
The following example (derived from the accepted answer) compiles on Apple clang version 13.1.6. Note that I had to put is_transparent both in NodeHash and NodeEq.
#include <unordered_set>
struct Node {
int id;
int count;
};
struct NodeEq {
using is_transparent = void;
bool operator() (Node const& a, Node const& b) const { return a.id == b.id; };
bool operator() (Node const& n, int const i) const { return n.id == i; };
bool operator() (int const i, Node const& n) const { return n.id == i; };
};
struct NodeHash {
using is_transparent = void;
using transparent_key_equal = NodeEq;
std::size_t operator() (Node const& n) const noexcept { return n.id; };
std::size_t operator() (int n) const noexcept { return n; };
};
using nodes_t = std::unordered_set< Node, NodeHash, NodeHash::transparent_key_equal >;
int main() {
nodes_t nodes;
nodes.find(1);
}
I have a POD with about 30 members of various types and I will be wanting to store thousands of the PODs in a container, and then sort that container by one of those members.
For example:
struct Person{
int idNumber;
....many other members
}
Thousands of Person objects which I want to sort by idNumber or by any other member I choose to sort by.
I've been researching this for a while today and it seems the most efficient, or at least, simplest, solution to this is not use struct at all, and rather use tuple for which I can pass an index number to a custom comparison functor for use in std::sort. (An example on this page shows one way to implement this type of sort easily, but does so on a single member of a struct which would make templating this not so easy since you must refer to the member by name, rather than by index which the tuple provides.)
My two-part question on this approach is 1) Is it acceptable for a tuple to be fairly large, with dozens of members? and 2) Is there an equally elegant solution for continuing to use struct instead of tuple for this?
You can make a comparator that stores a pointer to member internaly so it knows which member to take for comparison:
struct POD {
int i;
char c;
float f;
long l;
double d;
short s;
};
template<typename C, typename T>
struct Comp {
explicit Comp(T C::* p) : ptr(p) {}
bool operator()(const POD& p1, const POD& p2) const
{
return p1.*ptr < p2.*ptr;
}
private:
T C::* ptr;
};
// helper function to make a comparator easily
template<typename C, typename T>
Comp<C,T> make_comp( T C::* p)
{
return Comp<C,T>(p);
}
int main()
{
std::vector<POD> v;
std::sort(v.begin(), v.end(), make_comp(&POD::i));
std::sort(v.begin(), v.end(), make_comp(&POD::d));
// etc...
}
To further generalize this, make make_comp take a custom comparator, so you can have greater-than and other comparisons.
1) Is it acceptable for a tuple to be fairly large, with dozens of members?
Yes it is acceptable. However it won't be easy to maintain since all you'll have to work with is an index within the tuple, which is very akin to a magic number. The best you could get is reintroduce a name-to-index mapping using an enum which is hardly maintainable either.
2) Is there an equally elegant solution for continuing to use struct instead of tuple for this?
You can easily write a template function to access a specific struct member (to be fair, I didn't put much effort into it, it's more a proof of concept than anything else so that you get an idea how it can be done):
template<typename T, typename R, R T::* M>
R get_member(T& o) {
return o.*M;
}
struct Foo {
int i;
bool j;
float k;
};
int main() {
Foo f = { 3, true, 3.14 };
std::cout << get_member<Foo, float, &Foo::k>(f) << std::endl;
return 0;
}
From there, it's just as easy to write a generic comparator which you can use at your leisure (I'll leave it to you as an exercise). This way you can still refer to your members by name, yet you don't need to write a separate comparator for each member.
You could use a template to extract the sort key:
struct A
{
std::string name;
int a, b;
};
template<class Struct, typename T, T Struct::*Member>
struct compare_member
{
bool operator()(const Struct& lh, const Struct& rh)
{
return lh.*Member < rh.*Member;
}
};
int main()
{
std::vector<A> values;
std::sort(begin(values), end(values), compare_member<A, int, &A::a>());
}
Maybe you want to have a look at boost::multi_index_container which is a very powerful container if you want to index (sort) object by different keys.
Create a class which can use a pointer to a Person member data to use for comparison:
std::sort(container.begin(), container.end(), Compare(&Person::idNumber));
Where Compare is:
template<typename PointerToMemberData>
struct Compare {
Compare(PointerToMemberData pointerToMemberData) :
pointerToMemberData(pointerToMemberData) {
}
template<typename Type
bool operator()(Type lhs, Type rhs) {
return lhs.*pointerToMemberData < rhs.*pointerToMemberData
}
PointerToMemberData pointerToMemberData;
};