Unordered map hash function - c++

#include <iostream>
#include <unordered_map>
#include <utility>
#include <cmath>
#include <stdint.h>
template <class T>
struct Vec2
{
T x, y;
Vec2() : x(0) , y(0) { };
Vec2(T xn, T yn) : x(xn), y(yn) { };
bool operator==(const Vec2& vec) const
{
return (x == vec.x) and (y == vec.y);
}
};
struct HashVec2int
{
const uint32_t maximum;
// HashVec2int(const uint32_t& m) : maximum(m) { }
std::size_t operator()(const Vec2<int>& vec) const
{ return (vec.x * maximum) + vec.y; }
};
int main() {
typedef Vec2<int> iVec2;
std::unordered_map<std::pair<iVec2, iVec2>,
float, HashVec2int{300}> umap;
umap[std::make_pair(iVec2(1, 2), iVec2(2, 3))] = 3.14f;
std::cout << umap[std::make_pair(iVec2(1, 2), iVec2(2, 3))];
return 0;
}
I want to initialize a hash function with a maximum x value to hash my implementation of vector.
I changed the struct to a class a couple of times and even marked maximum manually inside of HashVec2int. It gave me cryptic errors.
.\main.cpp:35:32: error: type/value mismatch at argument 3 in template parameter list for 'template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> class std::unordered_map'
float, HashVec2int{300}> umap;
^
.\main.cpp:35:32: note: expected a type, got 'HashVec2int{300u}'
.\main.cpp:37:6: error: no match for 'operator[]' (operand types are 'int' and 'std::pair<Vec2<int>, Vec2<int> >')
umap[std::make_pair(iVec2(1, 2), iVec2(2, 3))] = 3.14f;
^
.\main.cpp:39:19: error: no match for 'operator[]' (operand types are 'int' and 'std::pair<Vec2<int>, Vec2<int> >')
std::cout << umap[std::make_pair(iVec2(1, 2), iVec2(2, 3))];
^
I followed cppreference tutorials on how to create a modified hash function.

You have a map with keys of pairs of iVecs but your hash is for single iVecs, that doesnt match. Though this will only be the next error you will be getting after fixing the current one.
It seems you try to pass an instance HashVec2int{300} as template argument when a type is expected.
If maximum does not change (it should not for the hash to be consistent) you can do it like this:
template <uint32_t maximum>
struct HashVec2int
{
std::size_t operator()(const Vec2<int>& vec) const
{ return (vec.x * maximum) + vec.y; }
};
int main() {
typedef Vec2<int> iVec2;
std::unordered_map<iVec2,
float, HashVec2int<200>> umap;
umap[iVec2(1, 2)] = 3.14f;
std::cout << umap[iVec2(1, 2)];
return 0;
}
If you do not want to make HashVec2int a template you can still use it, then use its type Hashvec2Int as argument for the unordered map template and pass an instance, eg HashVec2Int{200}, to one of the constructors that takes a hash instance: https://en.cppreference.com/w/cpp/container/unordered_map/unordered_map

Related

Build rtree with boost::geometry results in errors

I wrote this small program, following the boost documentation, but I get pages of errors when building it.
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <iostream>
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
typedef bg::model::d2::point_xy<double> point_2d;
class Foo
{
public:
point_2d position;
Foo(double x, double y) : position(x, y) {}
auto get() const { return position; }
};
int main()
{
bgi::rtree<Foo, bgi::quadratic<16>> rtree;
rtree.insert(Foo(1.0, 2.0));
rtree.insert(Foo(3.0, 4.0));
rtree.insert(Foo(5.0, 6.0));
rtree.insert(Foo(7.0, 8.0));
// Define a search box with a certain distance from a given point
point_2d search_point(0.0, 0.0);
double search_distance = 5.0;
point_2d lower_left(search_point.x() - search_distance, search_point.y() - search_distance);
point_2d upper_right(search_point.x() + search_distance, search_point.y() + search_distance);
bg::model::box<point_2d> search_box(lower_left, upper_right);
// Use the rtree to search for instances of Foo within the search box
std::vector<Foo> result;
rtree.query(bgi::intersects(search_box), std::back_inserter(result));
// Print the results
std::cout << "Found " << result.size() << " instances of Foo within the search box" << std::endl;
for (const auto& foo : result)
std::cout << "Foo at position (" << foo.position.x() << ", " << foo.position.y() << ")" << std::endl;
}
Here is the build:
clang++ --std=c++17 tree.cpp -lboost-geometry 2>&1 | head -n50
In file included from tree.cpp:1:
In file included from /usr/include/boost/geometry/index/rtree.hpp:49:
/usr/include/boost/geometry/index/indexable.hpp:64:5: error: no matching function for call to 'assertion_failed'
BOOST_MPL_ASSERT_MSG(
^~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/mpl/assert.hpp:454:51: note: expanded from macro 'BOOST_MPL_ASSERT_MSG'
# define BOOST_MPL_ASSERT_MSG( c, msg, types_ ) \
^
/usr/include/boost/mpl/assert.hpp:440:9: note: expanded from macro '\
BOOST_MPL_ASSERT_MSG_IMPL'
boost::mpl::assertion_failed<(c)>( BOOST_PP_CAT(mpl_assert_arg,counter)::assert_arg() ) \
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/mpl/assert.hpp:60:58: note: expanded from macro '\
BOOST_MPL_AUX_ASSERT_CONSTANT'
# define BOOST_MPL_AUX_ASSERT_CONSTANT(T, expr) enum { expr }
^~~~
/usr/include/boost/geometry/index/indexable.hpp:351:7: note: in instantiation of template class 'boost::geometry::index::detail::indexable<Foo, false>' requested here
: detail::indexable<Value>
^
/usr/include/boost/geometry/index/detail/translator.hpp:46:14: note: in instantiation of template class 'boost::geometry::index::indexable<Foo>' requested here
: public IndexableGetter
^
/usr/include/boost/geometry/index/detail/translator.hpp:74:22: note: in instantiation of template class 'boost::geometry::index::detail::translator<boost::geometry::index::indexable<Foo>, boost::geometry::index::equal_to<Foo> >' requested here
typedef typename IndexableGetter::result_type type;
^
/usr/include/boost/geometry/index/detail/translator.hpp:82:22: note: in instantiation of template class 'boost::geometry::index::detail::result_type<boost::geometry::index::detail::translator<boost::geometry::index::indexable<Foo>, boost::geometry::index::equal_to<Foo> > >' requested here
typename result_type<IndexableGetter>::type
^
/usr/include/boost/geometry/index/rtree.hpp:177:37: note: in instantiation of template class 'boost::geometry::index::detail::indexable_type<boost::geometry::index::detail::translator<boost::geometry::index::indexable<Foo>, boost::geometry::index::equal_to<Foo> > >' requested here
typedef typename index::detail::indexable_type<
^
tree.cpp:27:41: note: in instantiation of template class 'boost::geometry::index::rtree<Foo, boost::geometry::index::quadratic<16, 4>, boost::geometry::index::indexable<Foo>, boost::geometry::index::equal_to<Foo>, boost::container::new_allocator<Foo> >' requested here
bgi::rtree<Foo, bgi::quadratic<16>> rtree;
^
/usr/include/boost/mpl/assert.hpp:83:5: note: candidate function template not viable: no known conversion from 'boost::mpl::failed ************(boost::geometry::index::detail::indexable<Foo, false>::NOT_VALID_INDEXABLE_TYPE::************)(Foo)' to 'typename assert<false>::type' (aka 'mpl_::assert<false>') for 1st argument
int assertion_failed( typename assert<C>::type );
^
In file included from tree.cpp:1:
In file included from /usr/include/boost/geometry/index/rtree.hpp:28:
In file included from /usr/include/boost/geometry/algorithms/detail/comparable_distance/interface.hpp:23:
In file included from /usr/include/boost/geometry/geometries/concepts/check.hpp:28:
In file included from /usr/include/boost/geometry/geometries/concepts/box_concept.hpp:23:
In file included from /usr/include/boost/geometry/core/access.hpp:25:
In file included from /usr/include/boost/geometry/core/coordinate_type.hpp:20:
/usr/include/boost/geometry/core/point_type.hpp:45:5: error: no matching function for call to 'assertion_failed'
BOOST_MPL_ASSERT_MSG
^~~~~~~~~~~~~~~~~~~~
/usr/include/boost/mpl/assert.hpp:454:51: note: expanded from macro 'BOOST_MPL_ASSERT_MSG'
# define BOOST_MPL_ASSERT_MSG( c, msg, types_ ) \
Foo is not an indexable type. Meaning, mainly, that rtree doesn't know what geometry to index it by.
Let's make an IndexableGetter:
struct ByPos {
using result_type = point_2d;
result_type const& operator()(Foo const& f) const { return f.position; }
};
Now you can use it:
Live On Coliru
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <iostream>
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
using point_2d = bg::model::d2::point_xy<double> ;
using box = bg::model::box<point_2d>;
struct Foo {
point_2d position;
Foo(double x, double y) : position(x, y) {}
auto get() const { return position; }
struct ByPos {
using result_type = point_2d;
result_type const& operator()(Foo const& f) const { return f.position; }
};
};
auto intersecting(auto const& search, auto const& tree) {
std::vector<std::reference_wrapper<Foo const>> result;
tree.query(bgi::intersects(search), back_inserter(result));
return result;
}
int main() {
bgi::rtree<Foo, bgi::quadratic<16>, Foo::ByPos> rtree;
rtree.insert({1.0, 2.0});
rtree.insert({3.0, 4.0});
rtree.insert({5.0, 6.0});
rtree.insert({7.0, 8.0});
// box with given distance from center
auto makebox = [&](double d, point_2d c = {}) {
return box{{c.x() - d, c.y() - d}, {c.x() + d, c.y() + d}};
};
auto key = makebox(5.0);
std::cout << "Within " << bg::dsv(key) << ":\n";
for (Foo const& foo : intersecting(key, rtree))
std::cout << " - at " << bg::dsv(foo.position) << "\n";
}
Prints
Within ((-5, -5), (5, 5)):
- at (1, 2)
- at (3, 4)

Creating a vector of the type of std::any

Consider the following example
#include <iostream>
#include <any>
#include <vector>
#include <map>
#include <typeinfo>
typedef enum TYPE{
INT8=0,
INT16=1,
INT32=2
} TYPE;
int main()
{
std::map<TYPE, std::any> myMap;
myMap[TYPE::INT8] = (int8_t)0;
myMap[TYPE::INT16] = (int16_t)0;
myMap[TYPE::INT32] = (int32_t)0;
std::vector<decltype(myMap[TYPE::INT8])> vec;
}
I have a map in this example, going from some enum to std::any. I actually need a flexible data structure that can map from a specific type (enum TYPE in this case), to multiple data types (different types of int), hence the use of std::any.
Going ahead, I would like to ascertain the type of value given for the key and construct a vector with it. I tried the above code, and it runs into a compilation error because decltype will return std::any(correctly so).
I would want to extract the "true type" from the std::any and create that type of vector. How would I achieve that.
A small snippet of the compilation error is as follows -
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:63:26: error: forming pointer to reference type 'std::any&'
63 | typedef _Tp* pointer;
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:112:7: error: forming pointer to reference type 'std::any&'
112 | allocate(size_type __n, const void* = static_cast<const void*>(0))
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1293:7: error: 'void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = std::any&; _Alloc = std::allocator<std::any&>; value_type = std::any&]' cannot be overloaded with 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::any&; _Alloc = std::allocator<std::any&>; value_type = std::any&]'
1293 | push_back(value_type&& __x)
TIA
As suggested in the comments by #Ted Lyngmo, I think std::variant serves you better. Especially with C++-20's templated lambdas, the std::visit function can work wonders with these to get around the awkwardness of dealing with type enums and the like.
Note that you can not get around the runtime type detection. In any case, here is an example of how it can work.
#include <cstdint>
#include <iostream>
#include <variant>
#include <vector>
using VariantScalar = std::variant<
std::int8_t, std::int16_t, std::int32_t>;
using VariantVector = std::variant<
std::vector<std::int8_t>,
std::vector<std::int16_t>,
std::vector<std::int32_t>>;
VariantVector fill_vector(VariantScalar scalar, std::size_t n)
{
auto make_vector = [n]<class IntType>(IntType v) -> VariantVector {
return std::vector<IntType>(n, v);
};
return std::visit(make_vector, scalar);
}
void print_vector(const VariantVector& vec)
{
std::visit([]<class T>(const std::vector<T>& vec) {
for(const T& s: vec)
std::cout << s << ' ';
std::cout << '\n';
}, vec);
}
int main()
{
VariantScalar s(std::int8_t(1));
VariantVector vec = fill_vector(s, 5);
print_vector(vec);
}
Assuming you have the following enum definition:
enum class TYPE{
INT8=0,
INT16=1,
INT32=2
};
Then you can define a helper:
template <TYPE>
struct my_type {}; // Base case
template <>
struct my_type<TYPE::INT8> {
using type = int8_t;
};
template <>
struct my_type<TYPE::INT16> {
using type = int16_t;
};
template <>
struct my_type<TYPE::INT32> {
using type = int32_t;
};
template <TYPE t>
using my_type = typename my_type<t>::type;
That you can use for your vector
std::vector<my_type<TYPE::INT8>> vec;

How can I create a vector based on a variable type

I'm using a template function, which the goal is reciever a vector and a function, and return the function type.
template <typename T, typename Function>
auto apply(const std::vector<T>& V, const Function &F){
vector<Function> x; # ERROR HERE
return x;
}
But the IDE give me error (http://coliru.stacked-crooked.com/a/ee6ce2127e013a18):
/usr/local/include/c++/10.2.0/ext/new_allocator.h: In instantiation of 'class __gnu_cxx::new_allocator<double(double)>':
/usr/local/include/c++/10.2.0/bits/allocator.h:116:11: required from 'class std::allocator<double(double)>'
/usr/local/include/c++/10.2.0/bits/stl_vector.h:87:21: required from 'struct std::_Vector_base<double(double), std::allocator<double(double)> >'
/usr/local/include/c++/10.2.0/bits/stl_vector.h:389:11: required from 'class std::vector<double(double), std::allocator<double(double)> >'
main.cpp:10:22: required from 'auto apply(const std::vector<T>&, const Function&) [with T = int; Function = double(double)]'
main.cpp:19:39: required from here
/usr/local/include/c++/10.2.0/ext/new_allocator.h:96:7: error: 'const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = double(double); __gnu_cxx::new_allocator<_Tp>::const_pointer = double (*)(double); __gnu_cxx::new_allocator<_Tp>::const_reference = double (&)(double)]' cannot be overloaded with '_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = double(double); __gnu_cxx::new_allocator<_Tp>::pointer = double (*)(double); __gnu_cxx::new_allocator<_Tp>::reference = double (&)(double)]'
96 | address(const_reference __x) const _GLIBCXX_NOEXCEPT
| ^~~~~~~
/usr/local/include/c++/10.2.0/ext/new_allocator.h:92:7: note: previous declaration '_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = double(double); __gnu_cxx::new_allocator<_Tp>::pointer = double (*)(double); __gnu_cxx::new_allocator<_Tp>::reference = double (&)(double)]'
92 | address(reference __x) const _GLIBCXX_NOEXCEPT
| ^~~~~~~
main.cpp: In function 'int main(int, char**)':
main.cpp:19:31: error: conversion from 'vector<double(double),allocator<double(double)>>' to non-scalar type 'vector<double,allocator<double>>' requested
19 | vector<double> r = ::apply(v, seno);
| ~~~~~~~^~~~~~~~~
This is call of the main function.
double seno( double n ) { return sin(n); }
int main( int argc, char* argv[]) {
vector<int> v{ 1, 2, 3, 4, 5 };
vector<double> r = ::apply(v, seno);
cout << r;
return 0;
}
I don't know what I'm doing wrong, so How can I improve this method and pass trough this error?
EDIT: The purpse to generalize the in method insted of using double in the vector is because I want o re-use in another way. So I've generalize the most that I can.
vector<Function> x; // ERROR HERE defines a vector of function pointers. But that's not what you want - you want a vector of the return type of the function. And that's what decltype() is for.
In your apply function, F is the function to be called and T is the type of the values in the vector being passed in. That means T() is the default value of the items in the vector (in this case the default value of int is 0). Then, F(T()) would actually call the function with 0 and return something so decltype(F(T())) tells you the type of the thing returned.
That means you need to write vector<decltype(F(T()))> x; instead.
T() works because the type is int and it is default constructible. As #alterigel said in the comments std::declval<T>() is better when the type is not default constructible.
So vector<decltype(F(std::declval<T>()))> x; might be needed in some situations.
The whole program would look like:
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
template <typename T, typename Function>
auto apply(const std::vector<T>& V, const Function &F) {
vector<decltype(F(T()))> x;
for(auto a : V)
x.push_back(F(a));
return x;
}
double seno( double n ) { return sin(n); }
int main( int argc, char* argv[]) {
vector<int> v{ 1, 2, 3, 4, 5 };
vector<double> r = ::apply(v, seno);
for (auto a : r)
cout << a << " ";
return 0;
}
Try it here: https://onlinegdb.com/SknTsVaHO

Use a function pointer as template function type parameter?

#include <iostream>
#include <unordered_map>
#include <utility>
#include <typeinfo>
using namespace std;
class Handle{
public:
int val;
bool getAskPrice(int& tmp) const
{
tmp = val;
return true;
}
bool setAskPrice(int& tmp)
{
val = tmp;
return true;
}
};
template<class RT, class ARG>
struct convertToAFL{
static RT to_afl(ARG);
};
template<class RT, class ARG>
struct convertFromAFL{
static RT from_afl(ARG);
};
template<>
struct convertToAFL<float, int>
{
static float to_afl(int& value)
{
return static_cast<float>(value);
}
};
template<>
struct convertFromAFL<int, float>
{
static int from_afl(float& val)
{
return static_cast<int>(val);
}
};
struct Getter{
template<typename TICK_D, bool (Handle::*Getter)(TICK_D&) const, typename AFL_D>
static AFL_D getter(const Handle& handle)
{
TICK_D temp;
bool exists;
exists = (handle.*Getter)(temp);
AFL_D x = convertToAFL<AFL_D, TICK_D>::to_afl(temp);
return exists ? x : -1;
}
};
struct Setter{
template<typename TICK_D, bool (Handle::*Setter)(TICK_D&), typename AFL_D>
static void setter(Handle& handle, AFL_D& val)
{
TICK_D x;
x = convertFromAFL<TICK_D, AFL_D>::from_afl(val);
(handle.*Setter)(x);
}
};
int main()
{
Handle h;
float val = 20.0;
Setter::setter<int, &Handle::setAskPrice, float>(h, val);
std::cout<<Getter::getter<int, &Handle::getAskPrice, float>(h);
//std::pair<, &Setter::setter<int, &Handle::setAskPrice, float>> x;
return 0;
}
The above code works as expected, however, in the main() instead of calling the functions, how can I store the pointer to the templatized Setter:setter() and Getter::getter() ?
I m trying something like
std::pair<&Setter::setter<int, &Handle::setAskPrice, float>, &Getter::getter<int, &Handle::getAskPrice, float>(h)> func_pair;
And be able to call the functions later.
But i get an error saying
main.cpp: In function ‘int main()’:
main.cpp:85:118: error: type/value mismatch at argument 1 in template parameter list for ‘template struct std::pair’
std::pair<&Setter::setter<int, &Handle::setAskPrice, float>, &Getter::getter<int, &Handle::getAskPrice, float>(h)> func_pair;
^
main.cpp:85:118: note: expected a type, got ‘& setter’
main.cpp:85:118: error: template argument 2 is invalid
Static member functions are just a normal functions. You can store these pointers like this:
std::pair<void (*)(Handle& handle, float& val), float (*)(const Handle& handle)>
func_pair(&Setter::setter<int, &Handle::setAskPrice, float>, &Getter::getter<int, &Handle::getAskPrice, float>);
Your problem is that template parameter is a type, but you are passing a value (pointer) as an argument. Instead, you could use auto like this:
auto func_pair = std::make_pair(&Setter::setter<int, &Handle::setAskPrice, float>, &Getter::getter<int, &Handle::getAskPrice, float>);
Edit: if you are using C++03, std::make_pair() is still available, but not auto. You will need to describe the type manually with a series of typedefs.
You can use decltype to get the pointer type.
Example:
std::pair<int, decltype(&Setter::setter<int, &Handle::setAskPrice, float>)> x = {
1, &Setter::setter<int, &Handle::setAskPrice, float>
};
Prior to C++11:
std::pair<int, void(*)(Handle&, float&)> x(
1, &Setter::setter<int, &Handle::setAskPrice, float>
);

Adding a struct into a map

I'm having trouble adding a struct into a map. I don't really understand the error.
There are 2 errors:
I can't declare a map with 'struct' type
I can't use insert to 'insert' my struct into the map
What am I doing wrong?
#include <iostream>
#include <map>
int main()
{
typedef struct
{
std::string stringVar;
unsigned unsignedVar;
float floatVar;
} MyTypeDefStruct;
MyTypeDefStruct myTypeDefStruct;
myTypeDefStruct.stringVar = "myStr";
myTypeDefStruct.unsignedVar = 1000;
myTypeDefStruct.floatVar = -10.0;
float anotherFloat = -20.0;
std::map<MyTypeDefStruct, float> myMap;
myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
return 0;
}
error:
test.cpp: In function 'int main()':
test.cpp:21:36: error: template argument for 'template<class _Tp> struct std::less' uses local type 'main()::MyTypeDefStruct'
std::map<MyTypeDefStruct, float> myMap;
^
test.cpp:21:36: error: trying to instantiate 'template<class _Tp> struct std::less'
test.cpp:21:36: error: template argument 3 is invalid
test.cpp:21:36: error: template argument for 'template<class _T1, class _T2> struct std::pair' uses local type 'const main()::MyTypeDefStruct'
test.cpp:21:36: error: trying to instantiate 'template<class _T1, class _T2> struct std::pair'
test.cpp:21:36: error: template argument 4 is invalid
test.cpp:21:43: error: invalid type in declaration before ';' token
std::map<MyTypeDefStruct, float> myMap;
^
test.cpp:23:11: error: request for member 'insert' in 'myMap', which is of non-class type 'int'
myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
^
test.cpp:23:50: error: template argument for 'template<class _T1, class _T2> struct std::pair' uses local type 'main()::MyTypeDefStruct'
myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
^
test.cpp:23:50: error: trying to instantiate 'template<class _T1, class _T2> struct std::pair'
There are several issues in your code:
The struct should defined outside of the function main, can't see a reason why you want to define it there in this case, and since it is local inside of main, you can't use it anywhere else!
You are using the C-style typedef struct ... StructName instead of simply using struct MyStruct.
Your struct doesn't implement the operator<, hence, since std::map is an ordered map, and it doesn't have anyway to compare two keys (here, the key is your struct), it doesn't able to insert any pair.
Your struct doesn't implement the operator== which is important to actually retrieving the value of a certain key... You should be able to check if the keys are similar.
Another small fix - using std::make_pair instead of its ctor.
Your code should look like:
#include <iostream>
#include <map>
struct MyStruct
{
std::string stringVar;
unsigned unsignedVar;
float floatVar;
friend bool operator<(const MyStruct& l, const MyStruct& r)
{
return std::tie(l.stringVar, l.unsignedVar, l.floatVar)
< std::tie(r.stringVar, r.unsignedVar, r.floatVar);
}
friend bool operator==(const MyStruct& l, const MyStruct& r)
{
return std::tie(l.stringVar, l.unsignedVar, l.floatVar)
== std::tie(r.stringVar, r.unsignedVar, r.floatVar);
}
};
int main()
{
MyStruct my_struct;
my_struct.stringVar = "myStr";
my_struct.unsignedVar = 1000;
my_struct.floatVar = -10.0;
float anotherFloat = -20.0;
std::map<MyStruct, float> myMap;
myMap.insert(std::make_pair(my_struct, anotherFloat));
return 0;
}
How did I get to identifying the first problem? In the first error (always look at the first error, the others may be misleading!), it is written:
test.cpp:21:36: error: template argument for 'template<class _Tp> struct std::less' uses local type 'main()::MyTypeDefStruct'
std::map<MyTypeDefStruct, float> myMap;
Notice that the template initialization here is using main()::MyTypeDefStruct and not MyTypeDefStruct!!! These types are different, and the first is available only in the scope of main()!
The third point is because when you fix the first point, you will get:
error: no match for 'operator<' (operand types are 'const MyStruct' and 'const MyStruct')
The first problem is that map requires a way to compare two myTypeDefStructs.
You'll need to do is define operator< or std::less for your class, or pass a comparison functor to the map.
std::map<T>::insert uses a comparator to insert your elements but there is no one defined for your struct, hence try to use something like the following
#include <iostream>
#include <map>
struct MyTypeDefStruct
{
std::string stringVar;
unsigned unsignedVar;
float floatVar;
} ;
bool operator<(const MyTypeDefStruct& lhs, const MyTypeDefStruct& rhs){
return lhs.unsignedVar < rhs.unsignedVar;
}
int main()
{
MyTypeDefStruct myTypeDefStruct;
myTypeDefStruct.stringVar = "myStr";
myTypeDefStruct.unsignedVar = 1000;
myTypeDefStruct.floatVar = -10.0;
float anotherFloat = -20.0;
std::map<MyTypeDefStruct, float> myMap;
myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
return 0;
}
A sorted map needs a less operator (operator<) to sort the elements. You have to provide such operator or you have to set a sort function. One possible solution is to implement this operator:
#include <iostream>
#include <map>
struct MyTypeDefStruct {
std::string stringVar;
unsigned unsignedVar;
float floatVar;
};
bool operator<(const MyTypeDefStruct &lhs, const MyTypeDefStruct &rhs) {
if (lhs.stringVar < rhs.stringVar) return true;
if (lhs.stringVar > rhs.stringVar) return false;
if (lhs.unsignedVar < rhs.unsignedVar) return true;
if (lhs.unsignedVar > rhs.unsignedVar) return false;
if (lhs.floatVar < rhs.floatVar) return true;
return false;
}
int main() {
MyTypeDefStruct myTypeDefStruct;
myTypeDefStruct.stringVar = "myStr";
myTypeDefStruct.unsignedVar = 1000;
myTypeDefStruct.floatVar = -10.0;
float anotherFloat = -20.0;
std::map<MyTypeDefStruct, float> myMap;
myMap.insert(std::pair<MyTypeDefStruct, float> (myTypeDefStruct, anotherFloat));
return 0;
}