Blitz++ arrays as keys for maps - c++

I am trying to use blitz++ arrays, since I understand they generally offer higher performance than other forms of arrays. Is it possible to use blitz++ arrays as keys in a map? Trying
#include <map>
#include <blitz/array.h>
using namespace std;
map<blitz::Array<int,1>,int> testmap;
blitz::Array<int,1> B(3);
B = 1,2,3;
testmap.insert(make_pair(B,2));
does not compile. Here's the error:
In file included from /usr/include/c++/4.6/string:50:0,
/usr/include/c++/4.6/bits/stl_function.h: In member function ‘bool
std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp =
blitz::Array]’:
/usr/include/c++/4.6/bits/stl_function.h:236:22: error: cannot convert
‘blitz::BzBinaryExprResult,
blitz::Array >::T_result {aka
blitz::_bz_ArrayExpr, blitz::FastArrayIterator, blitz::Less > >}’ to
‘bool’ in return
Is this a matter of requiring a definition of the < operator, and if so, can/should I define it myself?
ANSWER
As suggested by Jimmy Thompson, a possible solution is to define:
struct MyComparison
{
bool operator() (const blitz::Array<int, 1> &lhs, const blitz::Array<int, 1> &rhs) const
{
if (lhs.size() < rhs.size()) {return true;}
else if (lhs.size() > rhs.size()) {return false;}
else
{
for (int i=0; i<lhs.size(); i++)
{
if (lhs(i)<rhs(i)) {return true;}
else if(lhs(i)>rhs(i)) {return false;}
}
}
}
};
Then
map<blitz::Array<int,1>,int, MyComparison> testmap;

The std::map documentation states that keys are compared using std::less by default. This just calls < and expects a return of true or false.
In order for you to use Blitz arrays as a key, you need to do one of the following:
Create your own comparison function, like std::less, which returns a boolean value stating whether one Blitz array is 'less' than the other (how you choose to determine this is up to you). Assuming you made this function and called it MyComparison, you would then create your map as follows map<blitz::Array<int,1>, int, MyComparison> testmap;.
struct MyComparison
{
bool operator() (const blitz::Array<int, 1> &lhs, const blitz::Array<int, 1> &rhs) const
{
// Blitz array comparison
}
};
Wrap your Blitz array type (blitz::Array<int,1>) in another object, overloading the < operator for that given object and then performing your comparison in there. For example:
class MyArrayWrapper
{
blitz::Array<int, 1> contents;
public:
// Constructor, etc.
bool operator<(const MyArrayWrapper &rhs) const
{
// Blitz array comparison
}
};
Then in your current file.
std::map<MyArrayWrapper,int> testmap;

Related

Call super operator== from a vector inherited class in C++

I'm trying to implement the compare operator of a class that inherits from vector.
I want it to compare first its own new attributes and then use the inherited operator from vector. This is an example:
struct A : vector<int> {
int a;
bool operator==(const A& other) {
return a == other.a && vector::operator==(other);
}
}
But I'm getting this error:
no member named 'operator==' in 'std::__1::vector<int, std::__1::allocator<int> >'
Same result with other classes from the STL, but it works well if I inherit from another class of my own.
This is the implementation of vector that I'm using:
inline _LIBCPP_INLINE_VISIBILITY
bool
operator==(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y)
{
const typename vector<_Tp, _Allocator>::size_type __sz = __x.size();
return __sz == __y.size() && _VSTD::equal(__x.begin(), __x.end(), __y.begin());
}
What I'm doing wrong?
vector's equality operator is a non-member function, which means you can't call it like that. You would be better off doing something like:
struct A : std::vector<int> {
int a;
bool operator==(const A& other) {
vector const& self = *this;
return a == other.a && self == other;
}
};
However, I wouldn't recommend inheriting from a standard container. Instead, you should have a std::vector<int> data member (composition over inheritance).

Failure on initialization of unordered map

and thanks for any input. I have a large dataset I am trying to manipulate. I am holding active elements in a list, and removing them when they become inactive. I want to hold all elements active and inactive in some data structure. Currently trying a map or an unordered_map, but am welcome to any suggestions.
I am compiling with
clang++ -std=c++11 -Wall -Wextra
When trying map:
#include <map>
std::map <class1, std::string> fullMap;
//and later...
for (std::list<class1>::iterator x = l.begin(); x != l.end(); x++)
{
fullMap[(*x)] = s
}
output reads:
error: invalid operands to binary expression ('const class1' and
'const class1') { return __x < __y; }
Even though I have overloaded the less than operator for class1.
This error originates at the overloaded bracket operators for map.
To circumvent I tried storing in an unordered_map.
#include <unordered_map>
std::unordered_map <class1, std::string> fullMap;
and the program fails at the initialization of fullMap with the even more confusing:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable_policy.h:830:23:
error: implicit instantiation of undefined template
'std::hash'
bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable_policy.h:1073:15: note: in instantiation of default argument for
'_Hashtable_ebo_helper<1, std::hash >' required here
private _Hashtable_ebo_helper<1, _H1>,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable_policy.h:1403:12: note: in instantiation of template class
'std::__detail::_Hash_code_base >, std::__detail::_Select1st, std::hash, std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash, true>' requested here : public
_Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash,
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/hashtable.h:175:14:
note: in instantiation of template class
'std::__detail::_Hashtable_base >, std::__detail::_Select1st, std::equal_to, std::hash,
std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Hashtable_traits >' requested here
: public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/unordered_map.h:100:18:
note: in instantiation of template class 'std::_Hashtable >,
std::allocator > >, std::__detail::_Select1st, std::equal_to, std::hash, std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy,
std::__detail::_Hashtable_traits >' requested here
_Hashtable _M_h;
^
main.cpp:34:44: note: in instantiation of template class
'std::unordered_map,
std::hash, std::equal_to,
std::allocator > > >' requested here std::unordered_map fullMap;
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/include/g++-v4/bits/functional_hash.h:58:12:
note: template is declared here
struct hash;
I tried to cut the code down only to the relevant chunks, but let me know if more information is needed. Thanks for reading, any help is appreciated.
//
// class1.hpp
// class
//
// Created by Roach on 9/3/16.
// Copyright © 2016 Roach. All rights reserved.
//
#ifndef class1_hpp
#define class1_hpp
#include <iostream>
#include <sstream>
#include <iomanip>
#include <ctime>
class class1
{
public:
class1 ();
class1 (const class1& t); // copy constructor
~class1 (); // destructor
class1& operator = (const class1& t); // assignment operator
bool operator == (const class1& t); // comparison operator
void setSetting2 (std::string t);
void setSetting1 (std::string p);
void setSetting3 (double d);
void setSetting4 (double d);
std::tm getTime () const;
std::string getSetting2 () const;
double getSetting3 () const;
double getSetting4 () const;
std::string getSetting1 () const;
void setSetting3End (double d);
void setSetting4End (double d);
double getSetting3End () const;
double getSetting4End () const;
double getSetting3flag () const;
double getSetting4flag () const;
double getSetting3final () const; // in pips
double getSetting4final () const; // in pips
void processList (class1::class1 t);
void setNew ();
//void dump (std::ostream& os) const;
private:
std::string setting1;
double setting4;
double setting3;
std::tm setting2;
double setting4End_;
double setting3End_;
bool setting4Flag_;
bool setting3Flag_;
double setting4final_; // in pips
double setting3final_; // in pips
};
// stream extraction operator
std::ostream& operator << (std::ostream& os, const class1& s);
std::istream& operator >> (std::istream& is, class1& t);
endif /* class1_hpp */
The following is my overloaded less than operator (I know it isn't the most succinct or efficient):
bool class1::operator< (const class1& t)
{
if (this->time_.tm_year < t.time_.tm_year) {return true;}
else if (this->time_.tm_year > t.time_.tm_year) {return false;}
else if (this->time_.tm_mon < t.time_.tm_mon) {return true;}
else if (this->time_.tm_mon > t.time_.tm_mon) {return false;}
else if (this->time_.tm_mday < t.time_.tm_mday) {return true;}
else if (this->time_.tm_mday > t.time_.tm_mday) {return false;}
else if (this->time_.tm_hour < t.time_.tm_hour) {return true;}
else if (this->time_.tm_hour > t.time_.tm_hour) {return false;}
else if (this->time_.tm_min < t.time_.tm_min) {return true;}
else if (this->time_.tm_min > t.time_.tm_min) {return false;}
else if (this->time_.tm_sec < t.time_.tm_sec) {return true;}
else {return false;}
}
The issue is that std::map<key_type, value_type> requires a properly defined operator< for key_type, in this case your operator< is not const specified so it is incompatible with std::map as this data structure requires that the comparator not alter the key object in any way. Thus the solution is to mark class1::operator< as const.
The second error notes that no hash function-object has been applied for use with std::unordered_map, this would require the following framework:
auto class1_hasher = [](const class1& c) -> std::size_t { return {some hash based on c}; }
std::unordered_map<class1, std::string, decltype(class1_hasher)> um;
I think the issue here is that you're breaking the preconditions required of the std::map and std::unordered_map interfaces.
In a std::map, the key type needs to be able to be compared using the less-than operator. This means that you either need to provide an overload of operator <, or provide a custom comparator when you're using the std::map type. Since you didn't provide a way of doing this with your type, the internal implementation of std::map wasn't able to make an expression of the form
somethingOfTypeClass1 < somethingElseOfTypeClass1
compile, hence your error message.
When you switched to std::unordered_map, you ran into trouble because, in order to store something as a key in an std::unordered_map, you need to specialize the std::hash template on your custom type because the internal works of an unordered_map require that the type is hashable. That's the second error you got.
To fix this issue, either
Define a custom operator < or comparator type for class1, then use std::map, or
Define a custom std::hash for class1, then use std::unordered_map.
Its difficult to suggest best data structure until we know the functionality requirement. But the Below code is working for me on GCC 4.9.3.
Please check your include files and syntax.
#include <iostream>
#include <string>
#include <map>
#include <unordered_map>
#include <list>
using namespace std;
int main()
{
//LIST
std::list<int> myList;
myList.push_front(1);
myList.push_front(2);
myList.push_front(3);
myList.push_front(4);
//STRING
string s = "Test";
//MAP
std::map <int, std::string> fullMap;
for (std::list<int>::iterator x = myList.begin(); x != myList.end(); x++)
{
fullMap.insert(std::make_pair(*x,s));
}
//UNORDERED MAP
std::unordered_map <int, std::string> fullUnorderedMap;
for (std::list<int>::iterator y = myList.begin(); y != myList.end(); y++)
{
fullUnorderedMap.insert(std::make_pair(*y,s));
}
//PRINTING
for(auto it = fullMap.begin(); it != fullMap.end(); ++it)
{
cout<<it->first<<" "<<it->second<<endl;
}
for(auto it = fullUnorderedMap.begin(); it != fullUnorderedMap.end(); ++it)
{
cout<<it->first<<" "<<it->second<<endl;
}
}

Comparison function not working for equal_range

I have the following piece of code, which saves structs into a boost::ptr_vector container. I am trying now to write a simple search function for this container via equal_range. I chose that function because I want a pointer to the element of the sequence (if it is found), or pointers to the lower and upper bound (if the element is not found):
struct COMP
{
bool operator()(const merkle_tree_node &LHS, const std::string& query){
return (LHS.word < query);
}
};
std::pair<boost::ptr_vector<merkle_tree_node>::iterator,
boost::ptr_vector<merkle_tree_node>::iterator>
search_tree(merkle_tree vWords, std::basic_string<char> query, size_t length)
{
return std::equal_range(vWords.begin(), vWords.begin()+(length-1),
query,
COMP());
}
Which I am calling via my main function as such:
std::basic_string<char> QUERY = "SOMETHING";
std::pair<boost::ptr_vector<merkle_tree_node>::iterator,
boost::ptr_vector<merkle_tree_node>::iterator> result =
search_tree(vWords, QUERY, vWords.size());
However, I am getting the following compilation error which I just can't seem to overcome:
In file included from /usr/include/c++/4.8/algorithm:62:0,
from vf-merkle.cpp:3:
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of ‘std::pair<_FIter, _FIter> std::equal_range(_FIter, _FIter, const _Tp&, _Compare) [with _FIter = boost::void_ptr_iterator<__gnu_cxx::__normal_iterator<void**, std::vector<void*, std::allocator<void*> > >, merkle_tree_node>; _Tp = std::basic_string<char>; _Compare = COMP]’:
vf-merkle.cpp:111:10: required from here
/usr/include/c++/4.8/bits/stl_algo.h:2668:36: error: no match for call to ‘(COMP) (const std::basic_string<char>&, merkle_tree_node&)’
else if (__comp(__val, *__middle))
^
vf-merkle.cpp:98:8: note: candidate is:
struct COMP
^
vf-merkle.cpp:100:7: note: bool COMP::operator()(const merkle_tree_node&, const string&)
bool operator()(const merkle_tree_node &LHS, const std::string& query){
^
vf-merkle.cpp:100:7: note: no known conversion for argument 1 from ‘const std::basic_string<char>’ to ‘const merkle_tree_node&’
Any ideas?
The short answer, is you need to provide both overloads for different orderings of the arguments
struct COMP
{
bool operator()(const merkle_tree_node &LHS, const std::string& query){
return (LHS.word < query);
}
bool operator()(const std::string& query,const merkle_tree_node &RHS){
return (query < RHS.word);
}
};
You need to do this because you are calling std::equal_range with the third argument of type string, while the iterators point to merkle_tree_node. This mixed comparison case requires you to provide additional overloads to handle the case where the string is the first argument, or when the string is the second argument. For completeness, you might want to consider adding the case where it's two instances of merkle_tree_node.
You call algorithm std:;equal_range passing to it std:;string as the third argument instead of an iterator, So your using of the algorithm is invalid. Read the description of std::equal_range before using it.

C++ STL wrong keys types

can't understand this: g++ compiler is angry on:
lengths.insert(pair<Deux,long>(d,one));
where
struct Deux {long big; long small};
map<Deux, long> lengths;
Deux d;
long one;
so, g++ said, that i miss operator<. after making overloaded operator< for struct Deux, i saw new interesting, but the same error:
map <long, Node*>ArrayOfNodes;
map <long, Node*>::iterator it;
for (it=ArrayOfNodes[Root]->nodes.begin();it<ArrayOfNodes[Root]->nodes.end();++it)
cout<<it->first<<endl;
also used structure Node:
struct Node {
long name;
long guest;
map <long,Node*>nodes;
/*bool operator<(const Node& node)const{
if ((*this).name<node.name) return true;
if ((*this).name>node.name) return false;
return (*this).guest<(*this).guest;
}*/
and error is:
no match for operator< in it < ((Path*)this)->Path::ArrayOfNodes.
std::map<_Key, _Tp, _Compare, _Alloc>::operator[] [with _Key = long int, _Tp = Node*,
_Compare = std::less<long int>, _Alloc = std::allocator<std::pair<const long int, Node*> >]
(((const long int&)((const long int*)(&((Path*)this)->Path::Root))))->Node::nodes.std::map<_Key, _Tp, _Compare, _Alloc>::end
[with _Key = long int, _Tp = Node*, _Compare = std::less<long int>, _Alloc = std::allocator<std::pair<const long int, Node*> >]()
The compiler complains that there is no operator < for Deux (I guess). The key must be a comparable class with operator < or you must pass a third template parameter to map - the comparator.
You see, the map keeps its keys in an ordered way. In order to order them, it needs a predicate. By default it tries to use operator <
try writing something like this:
bool operator < (Deux const & d1, Deux const & d2)
{
if(d1.big > d2.big)
return false;
if(d1.big < d2.big)
return true;
return d1.small < d2.small;
}
You did not mention the error message. Always post it!
So, I need to fork my post into two distinct sections.
Missing Declaration.
`error: 'Deux' was not declared in this scope`
That's because Deux is unknown at the point where you declare the map<>.
You need to declare Deux before map<Deux, long>, because map<Deux, long> requires the full definition of its parameters.
Missing Comparator.
`error: no match for 'operator<' in '__x < __y'`
That's because you haven't defined operator< for Deux.`
If you can define a logical operator<, i.e. one that is not arbitrarily chosen for sorting purposes, you could do it like this:
// must be in same namespace as Deux
bool operator< (Deux const &lhs, Deux const &rhs) {
return lhs.foo < rhs.foo;
}
If it needs access to non-public members, you can make it a member function:
bool operator< (Deux const &rhs) {
return this->foo < rhs.foo;
}
If such comparison would be arbitrary, do as Constantinius suggests.
Next time
You could have saved us time by posting your actual code or a minimal testcase, as well as by mentioning the error message.
My guess is that your struct is missing a compare function, to make an internal sorting of your Deux objects as keys. In a map, they have to be sorted.
This is the definition of std::map
template < class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key,T> > > class map;
So if you define a function like this:
bool compare_deux(Deux& a, Deux& b) {
return a.big < b.big;
}
and pass it as a template argument:
map <Deux, long, compare_deux> lengths;
you should be fine.
Use make_pair.
lengths.insert(make_pair<Deux,long>(d,one));
Just to add yet another reply, here's how I would implement Deux to be strictly ordered. We just use lexicographic ordering:
struct Deux
{
long big, small;
inline bool operator<(const Deux & o) const
{
return big < o.big || (!(o.big < big) && small < o.small);
}
};
std::map<Deux, T> m; // works now!
Alternatively, we could have spared ourselves the pain and said:
typedef std::pair<long, long> Deux;
std::map<Deux, T> m; // always works, lexicographic compare is provided by default
Always best not to reinvent the wheel!
Post a comment if you also want pair hashing using hash_combine to use unordered containers.
You need to declare the < operator or pass a comparison function on map creation.
struct Deux
{
long big;
long small
bool operator < (const Deux &n) const
{
if(big != n.big)
return big < n.big;
else
return small < n.small;
}
};

object in a set iterator

I can get a method of a class in a set iterator ?
#include <iostream>
#include <string>
#include <set>
class student{
public:
student(std::string n){
name=n;
}
void print(){
std::cout << name << std::endl;
}
bool operator < (const student & s1){ return true;}
bool operator = (const student & s1){ return true;}
private:
std::string name;
};
int main(){
std::set<student> studs;
studs.insert(student("name01"));
studs.insert(student("name02"));
std::set<student>::iterator it;
for(it = studs.begin(); it != studs.end(); it++)
(*it).print() ;
}
I get this error
students.cpp: In function ‘int main()’:
students.cpp:22: error: passing ‘const student’ as ‘this’ argument of ‘void student::print()’ discards qualifiers
/usr/include/c++/4.2.1/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = student]’:
/usr/include/c++/4.2.1/bits/stl_tree.h:982: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = student, _Val = student, _KeyOfValue = std::_Identity<student>, _Compare = std::less<student>, _Alloc = std::allocator<student>]’
/usr/include/c++/4.2.1/bits/stl_set.h:307: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [with _Key = student, _Compare = std::less<student>, _Alloc = std::allocator<student>]’
students.cpp:18: instantiated from here
/usr/include/c++/4.2.1/bits/stl_function.h:227: error: passing ‘const student’ as ‘this’ argument of ‘bool student::operator<(const student&)’ discards qualifiers
with
bool operator<(const student & s1) const { return true;}
bool operator==(const student & s1) const { return true;}
now work!! O_o',
#include <iostream>
#include <string>
#include <set>
class student{
public:
student(std::string n){
name=n;
}
void print() const {
std::cout << name << std::endl;
}
bool operator<(const student & s1) const { return true;}
bool operator==(const student & s1) const { return true;}
private:
std::string name;
};
int main(){
std::set<student> studs;
studs.insert(student("name01"));
studs.insert(student("name02"));
std::set<student>::iterator it;
for(it = studs.begin(); it != studs.end(); it++)
it->print() ;
}
You need to add a const qualifer to your print member function:
void print() const
{
std::cout << name << std::endl;
}
Objects in an std::set are necessarily const, since they are used as keys. When an object (or reference) is constant, you can only call member functions of that object which are declared with the const qualifier.
You also want const qualifiers on both the == and < operator overload functions. (And don't forget to change = to == as pointed out in the comments.)
Yes, though it->print() is more intuitive.
A naive world-view is that iterators are a bit like pointers. There is more to it than that, as explained here.
The most obvious form of iterator is a
pointer: A pointer can point to
elements in an array, and can iterate
through them using the increment
operator (++). But other forms of
iterators exist. For example, each
container type (such as a vector) has
a specific iterator type designed to
iterate through its elements in an
efficient way.
You want operator==, not operator=.
Your operator< definition violates the requirements of std::set, and is inconsistent with your operator<. That is, according to your operator<, nothing is equivalent, but according to your operator==, everything is equal. Operator< should define a irreflexive, transitive, and asymmetric (for non-equivalent values) relation.
Objects in a set are necessarily const, and so to call a function on such an object that function must be declared with the const qualifier. Specifically, print() should be declared void print() const.
Similarly, operator< should be declared with the const qualifier. std::set requires that operator< can be called with const objects. Another valid option would be to make operator< a non-member function and to take both objects by value (bad) or const reference (good).
While not required in your example, operator== should also be declared with the const qualifier.
Write your print() function like this:
void print() const //<---- note this 'const'
{
std::cout << name << std::endl;
}
Now your code should work now. :-)
By the way, such functions with const keyword appearing on the right side, are called const member function, as they cannot change any member-data of the class.
See this FAQ: [18.10] What is a "const member function"?
#include <iostream>
#include <set>
using namespace std;
class Boxer{
public:
string name;
int strength;
};
struct Comp{
bool operator()(const Boxer& a, const Boxer& b){
return a.strength > b.strength;
}
};
int main(){
Boxer boxer[3];
boxer[0].name="uday", boxer[0].strength=23;
boxer[1].name="manoj", boxer[1].strength=33;
boxer[2].name="rajiv", boxer[2].strength=13;
set< Boxer, Comp> s;
s.insert(boxer[0]);
s.insert(boxer[1]);
s.insert(boxer[2]);
set< Boxer, Comp>::iterator it = s.begin();
Boxer b = *it;
cout<<b.name;
//result is Manoj
return 0;
}