C++ user defined class gives compilation error with unordered set - c++

I have structure called NodeID. When I create the unordered_set for this, I get the following compilation error
Error C2678 binary '<': no operator found which takes a left-hand operand of type 'const _Ty' (or there is no acceptable conversion)
#include <iostream>
#include <unordered_set>
#include <map>
#include <set>
using namespace std;
struct NodeID
{
// Constructor
NodeID();
int mRgnID;
unsigned int mGID;
// Equal operator
bool operator == ( const NodeID& rhs ) const;
// Less than operator
bool operator < ( const NodeID& rhs ) const;
size_t operator()( const NodeID& n ) const noexcept
{
return n.mGID;
};
};
NodeID::NodeID()
{
mRgnID = -1;
mGID = 0;
}
//----------------------------------------------------------------------------------------
// Function : operator ==
// Purpose : Equal operator
bool NodeID::operator == ( const NodeID& rhs ) const
{
if (mRgnID != rhs.mRgnID)
return false;
if (mGID != rhs.mGID)
return false;
return true;
}
//----------------------------------------------------------------------------------------
// Function : operator <
// Purpose : Less than operator
bool NodeID::operator < ( const NodeID & rhs ) const
{
if (mRgnID < rhs.mRgnID)
return true;
else if (mRgnID > rhs.mRgnID)
return false;
else
{
if (mGID < rhs.mGID)
return true;
else if (mGID > rhs.mGID)
return false;
}
return false;
}
namespace std {
template<>
struct hash<NodeID>
{
std::size_t operator()( const NodeID& p ) const
{
return hash<int>()(p.mGID);
}
};
}
typedef std::unordered_set<NodeID> NodeSet;
int main()
{
NodeSet s;
NodeID n;
n.mGID = 2;
n.mRgnID = 0;
s.insert( n );
std::map<NodeSet, int> m;
m.insert( std::make_pair(s, 1) );
}
I have defined the less than operator in the NodeID structure

Related

requirements for custom container type to use with views

I start to play with std::ranges and want understand how views really work. So I try to write my own container and iterator type and want to use it in a view.
But something seems to be missing but the compiler only tells me that there is no begin() method inside the view but not why.
Example:
#include <iostream>
#include <array>
#include <ranges>
class MyFixedContainer;
class MyIterator
{
MyFixedContainer* ptr;
unsigned int offset;
public:
MyIterator( MyFixedContainer* ptr_, unsigned int offset_ ): ptr{ ptr_},offset{offset_}{}
bool operator==( MyIterator& other ) const
{
return ( ptr == other.ptr )&& ( offset == other.offset );
}
bool operator!=( MyIterator& other ) const
{
return !(*this == other);
}
MyIterator operator++()
{
offset++;
return *this;
}
MyIterator operator++(int)
{
MyIterator tmp = *this;
offset++;
return tmp;
}
int operator*() const;
};
class MyFixedContainer
{
std::array<int,4> arr={5,6,7,8};
public:
auto begin() { return MyIterator{ this, 0 }; }
auto end() { return MyIterator{ this, 4}; }
int Get( int offset ) const
{
return arr[ offset ];
}
};
int MyIterator::operator*() const
{
return ptr->Get( offset );
}
int main()
{
MyFixedContainer c;
// Container type itself works:
for ( int i: c )
{
std::cout << i << std::endl;
}
// Try to use with std::ranges
auto even = [] (int i) { return 0 == i % 2; };
auto y = std::views::filter(c, even);
auto b = y.begin(); // << error message
}
Compiles with
main.cpp:90:16: error: 'struct std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::__adaptor::_RangeAdaptor<_Callable::operator()<{MyFixedContainer&, main()::<lambda(int)>&}>::<lambda(_Range&&)> >' has no member named 'begin'
90 | auto b = y.begin();
https://godbolt.org/z/doW76j
MyIterator does not model std::input_or_output_iterator because:
It needs to be default constructible.
std::iter_difference_t<MyIterator> must be valid, and
the pre-increment operator must return a reference.
MyIterator is not a std::sentinel_for<MyIterator, MyIterator> because its operators == and != take references instead of const references.
MyIterator does not satisfy std::input_iterator, which requires std::iter_value_t to be valid.
Fixing all of the above:
#include <iostream>
#include <array>
#include <ranges>
class MyFixedContainer;
class MyIterator
{
MyFixedContainer* ptr;
unsigned int offset;
public:
using difference_type = int;
using value_type = int;
MyIterator() = default;
MyIterator( MyFixedContainer* ptr_, unsigned int offset_ ): ptr{ ptr_},offset{offset_}{}
bool operator==( MyIterator const & other ) const
{
return ( ptr == other.ptr )&& ( offset == other.offset );
}
bool operator!=( MyIterator const & other ) const
{
return !(*this == other);
}
MyIterator &operator++()
{
offset++;
return *this;
}
MyIterator operator++(int)
{
MyIterator tmp = *this;
offset++;
return tmp;
}
int operator*() const;
};
class MyFixedContainer
{
std::array<int,4> arr={5,6,7,8};
public:
auto begin() { return MyIterator{ this, 0 }; }
auto end() { return MyIterator{ this, 4}; }
int Get( int offset ) const
{
return arr[ offset ];
}
};
int MyIterator::operator*() const
{
return ptr->Get( offset );
}
int main()
{
MyFixedContainer c;
// Container type itself works:
for ( int i: c )
{
std::cout << i << std::endl;
}
// Try to use with std::ranges
auto even = [] (int i) { return 0 == i % 2; };
static_assert(std::input_or_output_iterator<MyIterator>);
static_assert(std::ranges::input_range<MyFixedContainer>);
auto y = c | std::views::filter(even);
auto b = y.begin(); // << OK
}
The error messages are much clearer if you static_assert every concept that your container/iterator has to model.

Passing set to templatised function

Here's my complete working code
class Point2D
{
protected:
int x, y;
public:
Point2D(int x_, int y_) : x(x_), y(y_)
{
}
int getX() const
{
return x;
}
int getY() const
{
return y;
}
bool operator< (const Point2D & pointObj) const
{
if(x == pointObj.getX() && y == pointObj.getY())
return false;
return pointObj.getX() == x ? true : x < pointObj.getX();
}
};
template<typename T, typename U>
void printSet(const set<T>& setToPrint)
{
set<T, U> pSet;
for(typename set<T>::iterator it = setToPrint.begin(); it != setToPrint.end(); it++)
{
pSet.insert(*it);
}
for(typename set<T,U>::iterator it = pSet.begin(); it != pSet.end(); it++)
{
//here print the element
}
}
int main()
{
set<Point2D> setP2;
setP2.insert(Point2D(1,3));
setP2.insert(Point2D(3,2));
int i = 1;
if(i==1)
{
printSet<Point2D, std::less<Point2D > >(setP2);
i++;
}
if(i==2)
{
printSet<Point2D, std::greater<Point2D > >(setP2);
}
}
It produces a bunch of errors from template code, but I think below is the primary one
/usr/include/c++/5/bits/stl_function.h:377:20: error: no match for ‘operator>’ (operand types are ‘const Point2D’ and ‘const Point2D’)
/usr/include/c++/5/bits/stl_function.h:377:20: note: ‘const Point2D’ is not derived from ‘const std::pair<_T1, _T2>’
What is wrong with the code?
In order to be able to create std::set<Point2D, std::greater<Point2D>>, you need to implement operator> between two objects of type Point2D.
Add a member funtion similar to operator< in the class to resolve the problem.
Suggestion for improvement
The operator< function can be simplified to user fewer compare operations.
bool operator< (const Point2D & pointObj) const
{
if ( x != pointObj.x )
{
return ( x < pointObj.x );
}
return ( y < pointObj.y );
}
The operato> function can be similarly implemented as:
bool operator> (const Point2D & pointObj) const
{
if ( x != pointObj.x )
{
return ( x > pointObj.x );
}
return ( y > pointObj.y );
}
You have implemented the < operator, not the >. C++ is pretty particular about that kind of thing. Implement operator> and you should be all set.
You can do that in terms of operator< if you like:
bool operator> (const Point2D & pointObj) const
{
if(x == pointObj.getX() && y == pointObj.getY())
return false;
return pointObj < this;
}
You can see more examples here.

std::variant, a wrapper class, and 'conversion from ... to non-scalar type ... requested'

I have mutually recursive variant types: Value, Array, and Object. The crux of the matter is that I can assign one of the variant types to a Value when it is nested within an Array or Object, which can both contain Value. I cannot assign directly to a Value. The main() function code at the bottom should make this clear. The compiler (GNU GCC 7.2) gives me errors like:
error: conversion from 'JSON::Integer {aka long unsigned int}' to non-scalar type 'JSON::Value' requested
Value v = Integer( 7 );
and oddly does not provide any additional information about assignment operator candidates or anything else. Further, it isn't clear to me how assignment operators I have defined in Value are affecting this problem. Complete working example code follows. Any assignment of one of the variant types directly to a Value type in main() causes a compiler error just like the one above for the Integer type.
Thanks in advance!
Object Class
#ifndef JSON_OBJECT_HPP
#define JSON_OBJECT_HPP
#include <iomanip>
#include <string>
#include <unordered_map>
#include "Value.hpp"
namespace JSON {
class Object {
public:
using Key = std::string;
private:
using values_t = std::unordered_map<Key,Value>;
values_t values;
public:
Object() = default;
Value & operator[]( Key const & key ) {
auto it = values.emplace( key, Value() );
return it.first->second;
}
Value const & operator[]( Key const & key ) const {
auto it = values.find( key );
return it->second;
}
bool has_key( Key const & key ) const {
auto it = values.find( key );
return it != values.end();
}
bool operator==( Object const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Object const & lhs, Object const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Object const & object ) {
os << '{';
auto begin = object.begin();
auto end = object.end();
if( begin != end ) {
os << std::quoted( begin->first ) << ':' << begin->second;
}
while( ++begin != end ) {
os << ',' << std::quoted( begin->first ) << ':' << begin->second;
}
os << '}';
}
}
#endif
Array Class
#ifndef JSON_ARRAY_HPP
#define JSON_ARRAY_HPP
#include <vector>
#include "types.hpp"
#include "Value.hpp"
namespace JSON {
std::ostream & operator<<( std::ostream &, Value & );
class Array {
private:
using values_t = std::vector<Value>;
values_t values;
public:
using Key = values_t::size_type;
Array() = default;
Value & operator[]( Key key ) {
if( !has_key( key ) ) {
values.resize( key + 1 );
}
return values[key];
}
Value const & operator[]( Key key ) const {
return values[key];
}
bool has_key( Key key ) const {
return key < values.size();
}
bool operator==( Array const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Array const & lhs, Array const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Array const & array ) {
os << '[';
auto begin = array.begin();
auto end = array.end();
if( begin != end ) {
os << *begin;
}
while( ++begin != end ) {
os << ',' << *begin;
}
os << ']';
}
}
#endif
Value Class
#ifndef JSON_VALUE_HPP
#define JSON_VALUE_HPP
#include <iomanip>
#include <type_traits>
#include <variant>
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include "types.hpp"
namespace JSON {
class Object;
class Array;
bool operator==( Object const & lhs, Object const & rhs );
bool operator==( Array const & lhs, Array const & rhs );
std::ostream & operator<<( std::ostream &, Object const & object );
std::ostream & operator<<( std::ostream &, Array const & array );
template<class T> struct always_false : std::false_type {};
class Value {
private:
using variant_t = std::variant<Undefined,String,Integer,Number,boost::recursive_wrapper<Object>,boost::recursive_wrapper<Array> >;
variant_t data;
friend std::ostream & operator<<( std::ostream & os, Value const & value );
public:
Value() = default;
bool operator==( Value const & rhs ) const {
return std::visit(
[]( auto && lhs, auto && rhs ) -> bool {
using lhsT = std::decay_t<decltype( lhs )>;
using rhsT = std::decay_t<decltype( rhs )>;
if constexpr ( std::is_same_v< lhsT, rhsT> ) {
if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Object> > ) {
return lhs.get() == rhs.get();
} else if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Array> > ) {
return lhs.get() == rhs.get();
} else {
return lhs == rhs;
}
} else {
return false;
}
},
data,
rhs.data
);
}
Value & operator=( String const & rhs ) {
data = rhs;
return *this;
}
Value & operator=( Integer const & rhs ) {
data = rhs;
return *this;
}
Value & operator=( Object const & rhs ) {
data = rhs;
return *this;
}
Value & operator=( Array const & rhs ) {
data = rhs;
return *this;
}
};
std::ostream & operator<<( std::ostream & os, Value const & value ) {
std::visit(
[&os]( auto && arg ) {
using T = std::decay_t<decltype( arg )>;
if constexpr ( std::is_same_v< T, Undefined > ) {
os << "undefined";
} else if constexpr ( std::is_same_v< T, String > ) {
os << std::quoted( arg );
} else if constexpr ( std::is_same_v< T, Integer > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, Number > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Object> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Array> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, Boolean > ) {
os << (arg == false ? "false" : "true");
} else if constexpr ( std::is_same_v< T, Null > ) {
os << "null";
} else {
static_assert( always_false<T>::value, "non-exhaustive visitor" );
}
},
value.data
);
}
}
#endif
Type Definitions
#ifndef TYPES_HPP
#define TYPES_HPP
namespace JSON {
template <typename Tag> struct Literal {
bool operator==( Literal const & ) const {
return true;
}
bool operator<( Literal const & ) const {
return false;
}
};
using String = std::string;
using Integer = uint64_t;
using Number = double;
class Object;
class Array;
using Boolean = bool;
using Null = Literal<struct tag_null>;
using Undefined = Literal<struct tag_undefined>;
}
#endif
Main Code
#include <iostream>
#include "Array.hpp"
#include "Object.hpp"
#include "Value.hpp"
using namespace JSON;
int main() {
Object o;
o["fun"] = "what?"; // compiles fin
o["stuff"] = "yeah!"; // compiles fine
o["inttest"] = Integer( 44 ); // compiles fine
Array a;
a[2] = "yo"; // compiles fine
a[3] = Integer( 6 ); // compiles fine
o["arrtest"] = a;
// Value v = a; // fails to compile
Value v = Integer( 7 ); // fails to compile
std::cout << v;
std::cout << o << "\n";
std::cout << a << "\n";
return 0;
}
This was a bad question with an embarrassing oversight. As the commenter pointed out, the problematic lines in main() were initializations rather than assignments. Providing the appropriate constructors solved the problem. For completeness, corrected code follows. It compiles and works fine under GNU GCC 7.2.
Object Class
#ifndef JSON_OBJECT_HPP
#define JSON_OBJECT_HPP
#include <iomanip>
#include <string>
#include <unordered_map>
#include "Value.hpp"
namespace JSON {
class Object {
public:
using Key = std::string;
private:
using values_t = std::unordered_map<Key,Value>;
values_t values;
public:
Object() = default;
Value & operator[]( Key const & key ) {
auto it = values.emplace( key, Value() );
return it.first->second;
}
Value const & operator[]( Key const & key ) const {
auto it = values.find( key );
return it->second;
}
bool has_key( Key const & key ) const {
auto it = values.find( key );
return it != values.end();
}
bool operator==( Object const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Object const & lhs, Object const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Object const & object ) {
os << '{';
auto begin = object.begin();
auto end = object.end();
if( begin != end ) {
os << std::quoted( begin->first ) << ':' << begin->second;
}
while( ++begin != end ) {
os << ',' << std::quoted( begin->first ) << ':' << begin->second;
}
os << '}';
}
}
#endif
Array Class
#ifndef JSON_ARRAY_HPP
#define JSON_ARRAY_HPP
#include <vector>
#include "types.hpp"
#include "Value.hpp"
namespace JSON {
std::ostream & operator<<( std::ostream &, Value const & );
class Array {
private:
using values_t = std::vector<Value>;
values_t values;
public:
using Key = values_t::size_type;
Array() = default;
Value & operator[]( Key key ) {
if( !has_key( key ) ) {
values.resize( key + 1 );
}
return values[key];
}
Value const & operator[]( Key key ) const {
return values[key];
}
bool has_key( Key key ) const {
return key < values.size();
}
bool operator==( Array const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Array const & lhs, Array const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Array const & array ) {
os << '[';
auto begin = array.begin();
auto end = array.end();
if( begin != end ) {
os << *begin;
}
while( ++begin != end ) {
os << ',' << *begin;
}
os << ']';
}
}
#endif
Value Class
#ifndef JSON_VALUE_HPP
#define JSON_VALUE_HPP
#include <iomanip>
#include <type_traits>
#include <variant>
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include "types.hpp"
namespace JSON {
class Object;
class Array;
bool operator==( Object const & lhs, Object const & rhs );
bool operator==( Array const & lhs, Array const & rhs );
std::ostream & operator<<( std::ostream &, Object const & object );
std::ostream & operator<<( std::ostream &, Array const & array );
template<class T> struct always_false : std::false_type {};
class Value {
private:
using variant_t = std::variant<Undefined,String,Integer,Number,boost::recursive_wrapper<Object>,boost::recursive_wrapper<Array> >;
variant_t data;
friend std::ostream & operator<<( std::ostream & os, Value const & value );
public:
Value() = default;
template <typename T> Value( T const & rhs ) : data( rhs ) {}
bool operator==( Value const & rhs ) const {
return std::visit(
[]( auto && lhs, auto && rhs ) -> bool {
using lhsT = std::decay_t<decltype( lhs )>;
using rhsT = std::decay_t<decltype( rhs )>;
if constexpr ( std::is_same_v< lhsT, rhsT> ) {
if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Object> > ) {
return lhs.get() == rhs.get();
} else if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Array> > ) {
return lhs.get() == rhs.get();
} else {
return lhs == rhs;
}
} else {
return false;
}
},
data,
rhs.data
);
}
};
std::ostream & operator<<( std::ostream & os, Value const & value ) {
std::visit(
[&os]( auto && arg ) {
using T = std::decay_t<decltype( arg )>;
if constexpr ( std::is_same_v< T, Undefined > ) {
os << "undefined";
} else if constexpr ( std::is_same_v< T, String > ) {
os << std::quoted( arg );
} else if constexpr ( std::is_same_v< T, Integer > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, Number > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Object> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Array> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, Boolean > ) {
os << (arg == false ? "false" : "true");
} else if constexpr ( std::is_same_v< T, Null > ) {
os << "null";
} else {
static_assert( always_false<T>::value, "non-exhaustive visitor" );
}
},
value.data
);
}
}
#endif
Type Definitions
#ifndef JSON_TYPES_HPP
#define JSON_TYPES_HPP
namespace JSON {
template <typename Tag> struct Literal {
bool operator==( Literal const & ) const {
return true;
}
bool operator<( Literal const & ) const {
return false;
}
};
using String = std::string;
using Integer = uint64_t;
using Number = double;
class Object;
class Array;
using Boolean = bool;
using Null = Literal<struct tag_null>;
using Undefined = Literal<struct tag_undefined>;
}
#endif
Main Code
#include <iostream>
#include "Array.hpp"
#include "Object.hpp"
#include "Value.hpp"
using namespace JSON;
int main() {
Object o;
o["fun"] = "what?";
o["stuff"] = "yeah!";
o["inttest"] = Integer( 44 );
Array a;
a[2] = "yo";
a[3] = Integer( 6 );
o["arrtest"] = a;
// Value v = a;
Value v = Integer( 7 );
std::cout << v << "\n";
std::cout << o << "\n";
std::cout << a << "\n";
return 0;
}

operator <= overloading for 2 classes and converting ctor

I have a little problem, which the Visual Studio compiler don't seem to be bothered by, but do in eclipse and g++.
I have 2 classes, Card and CardDeck. I do have the operator <= for 2 Carddecks as parameters and do not for 2 cards. I have a converting ctor, which converts Card to a Deck.
So the problem is when I do:
card1 <= card2
Which does work fine in visual, as it converts the left part to deck, then converts the right and then does the comparing.
In g++ it says:
no match for 'operator<=' (operand types are 'Card' and 'Card')
But there shouldn't be one. as I said I want the convert ctor would convet both sides and do the compare?
Any explanation and solution for this ?
Edit(the operator and ctor declaration and code):
CardDeck(const Card&);
friend bool operator<=(const CardDeck&, const CardDeck&);
CardDeck::CardDeck(const Card& card){
_Deck.push_back(card);
}
Here's a quick&dirty of what I think you are trying to do:
#include <iostream>
struct Element
{
int x;
Element() :x(0) {}
virtual ~Element() {}
};
struct Container
{
Element elems[10];
int n;
Container() { n=0; }
Container(const Element &e) { elems[0]=e; n=1; }
virtual ~Container() {}
friend bool operator<=(const Container &l, const Container &r);
};
bool operator<=(const Container &l, const Container &r)
{
if (l.n<=r.n) { std::cout << "less/equ\n"; return true; }
else { std::cout << "greater\n"; return false; }
}
int main(int argc, const char *argv[])
{
//Container container;
Element a, b;
if (a<=b) std::cout << "okay\n"; else std::cout << "fail\n";
return 0;
}
It works fine with gcc.
Deck(card1) <= Deck(card2)
Make operator<= (operand types are 'Card' and 'Card') override cause you use(mean) that in card1 <= card2 expression. Your code have architecture errors.
Update:
struct Card
{
bool operator<( const Card& right ) const;
};
struct Deck
{
std::vector<Card> m_arr;
Deck() = default;
Deck( const Card& conversion )
{
m_arr.push_back( conversion );
}
bool operator<( const Deck& right ) const;
};
bool Card::operator<( const Card& right ) const
{
return false;
}
bool Deck::operator<( const Deck& right ) const
{
bool result = false;
if(m_arr.size() < right.m_arr.size())
{
result = true;
}
else if(!m_arr.empty() && m_arr.size() == right.m_arr.size() )
{
result = true;
std::vector<Card>::const_iterator it = right.m_arr.begin();
std::vector<Card>::const_iterator it2 = m_arr.begin();
for(; it2 != m_arr.end(); ++it, ++it2 )
{
if((*it) < (*it2))
{
result = false;
break;
}
}
}
return result;
}

STXXL: How to sort Vector of pairs on second element?

Similar Question is available here: How do I sort a vector of pairs based on the second element of the pair? but I am interested in External Memory Sorting.
I have tried using the analogies from Internal Memory Sorting but the error occurs in sorter_stream.h file of STXXL as:
My code :
#include <iostream>
#include <stxxl/vector>
#include <stxxl/sorter>
#include <limits>
using namespace std;
typedef std::pair<int,int> my_pair;
struct my_comparator
{
bool operator()(const my_pair& left, const my_pair& right)
{
return left.first < right.first;
}
int min_value() const
{
return std::numeric_limits<int>::min();
}
int max_value() const
{
return std::numeric_limits<int>::max();
}
};
int main()
{
typedef stxxl::sorter<my_pair, my_comparator> sorter_type;
sorter_type int_sorter(my_comparator(), 64 * 1024 * 1024);
for (int i = 10; i > 0; i--)
{
int_sorter.push(my_pair(i,i+10));
}
int_sorter.sort(); // sort elements (in ascending order)
while (!int_sorter.empty())
{
std::cout << (*int_sorter).first << " "<<(*int_sorter).second<<endl;
++int_sorter;
}
return 0;
}
Error :
sort_stream.h(481): error C2679: binary '=' : no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion)
UPDATE:
Changing the return type of min_value(),max_value() function to my_pair as:
struct my_comparator
{
bool operator()(const my_pair& left, const my_pair& right)
{
return left.first < right.first;
}
my_pair min_value() const
{
return my_pair(std::numeric_limits<int>::min(),std::numeric_limits<int>::min());
}
my_pair max_value() const
{
return my_pair(std::numeric_limits<int>::max(),std::numeric_limits<int>::max());
}
};
gives the following Error:
sort_helper.h(94): error C3848: expression having type 'const my_comparator' would lose some const-volatile qualifiers in order to call 'bool my_comparator::operator ()(const my_pair &,const my_pair &)'
P.S. : Being a novice (Reputation<50) , I am not allowed to comment, that's why writing a new Question.
Got the following example in STXXL:Sorter Section which addresses the same problem.
Code:
#include <stxxl/sorter>
#include <stxxl/stats>
#include <stxxl/timer>
#include <stxxl/random>
#include <limits>
struct TwoInteger
{
int i, j;
TwoInteger()
{ }
TwoInteger(int _i, int _j)
: i(_i), j(_j)
{ }
};
struct TwoIntegerComparator
{
bool operator () (const TwoInteger& a, const TwoInteger& b) const
{
return a.i < b.i;
}
TwoInteger min_value() const
{
return TwoInteger(std::numeric_limits<int>::min(), std::numeric_limits<int>::min());
}
TwoInteger max_value() const
{
return TwoInteger(std::numeric_limits<int>::max(), std::numeric_limits<int>::max());
}
};
int main()
{
// template parameter <ValueType, CompareType, BlockSize(optional), AllocStr(optional)>
typedef stxxl::sorter<TwoInteger, TwoIntegerComparator, 1*1024*1024> sorter_type;
// create sorter object (CompareType(), MainMemoryLimit)
sorter_type int_sorter(TwoIntegerComparator(), 64 * 1024 * 1024);
stxxl::random_number32 rand32;
stxxl::timer Timer1;
Timer1.start();
// insert random numbers from [0,100000)
for (size_t i = 0; i < 1000; ++i)
{
int_sorter.push(TwoInteger(rand32() % 100000, (int)i)); // fill sorter container
}
Timer1.stop();
STXXL_MSG("push time: " << (Timer1.mseconds() / 1000));
stxxl::timer Timer2;
Timer2.start();
int_sorter.sort(); // switch to output state and sort
Timer2.stop();
STXXL_MSG("sort time: " << (Timer2.mseconds() / 1000));
// echo sorted elements
while (!int_sorter.empty())
{
std::cout << int_sorter->i << " "; // access value
++int_sorter;
}
return 0;
}