I have a pair: typdef pair <unsigned char *, vector<int>> pair_t
I need to implement my own comparison function for that map, so I tried :
struct myCmp
{
int operator()(unsigned char arr_1[10], unsigned char arr_2[10])
{
return memcmp(arr_1, arr_2, 10);
}
};
typdef pair <unsigned char *, vector<int>, **myCmp**> pair_t;
pair_t data(someCharArr, someIntVector);
The error message I get is:
wrong number of template argument (3 should be 2)
I did the same thing with map and it was fine.
How can create my own compare function for pair?
How can I be sure that the pair_t data(someCharArr, someIntVector); will find the correct key (in case of char * as key)?
Thanks.
You seem to be confused about responsibilities of different classes. It's not the std::pair that needs to worry about how to compare pairs together, it's the std::map who needs to worry about how to sort its keys.
typedef std::map<unsigned char*, std::vector<int>, myCmp> map_t;
From how you implement the comparison function and your comment on why you can't use strings, I actually recommend using a std::array instead of a unsigned char *. Your code then looks more like:
typedef std::map<std::array<unsigned char, 10>, std::vector<int> > map_t;
This works because std::array implements all the comparison operators allowing you to use them as keys in a map.
This is going off of the fact that you seem to know the length of your array at compile time, and that it is always 10. If you don't actually know the length of your arrays at compile time, then you would use a std::vector<unsigned char> instead of the std::array.
std::pair is just a struct with two members, It have no comparison object built in.
You may be confused for a comparison object given for std::map (which in its turn, holds sequence of std::pair).
Related
I want to use std::map to store pointers to a struct by using two ints as the key lookup, e.g.:
std::map<int, int, my_struct*> my_map;
Ideally I would like to write code similar to:
struct my_struct* test1 = get_struct_ptr();
my_map[1, 5] = test1;
Currently I get an error for the my_map definition:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/map:524:17:
error: called object type 'my_struct *' is not a function or function pointer
Is there a way to do this with std::map or is there another type that can handle this requirement?
A map is always from one type to another. You can create a type to store two ints for keys using std::pair<int, int>, so:
std::map<std::pair<int, int>, my_struct*> my_map;
my_map[{1, 5}] = test1;
Alternatively, you could use a std::tuple<int, int>, a std::array<int, 2>, or a struct with two int data members (but then you'd have to "teach" the map how to compare such structs by withing your own operator<; lots of existing questions & answers go into detail about how to do this).
I tried to insert a pair of values into map that's declared as :
unordered_map <unsigned int, std::string> map;
and when I insert the combination of 2 strings to and an unsigned int to map:
map.insert(std::make_pair(count,str1.append(str2)));
and Xcode say there's "no matching member function for call to 'insert'". I looked at the overload list, and I am not sure which one I should use in this case. Can someone please tell me?
Update: this problem is caused by unsuccesful typedef. I now changed map and defined it as unordered_map<usigned int, string>
The only thing you can insert into
std::unordered_map <unsigned int, objects> map;
is a
std::pair<unsigned int, objects>
You seem to be inserting
std::pair<unsigned int, std::string>
which will not work unless a std::string is implicitly convertible to objects.
If there is a implicit conversion from std::string to objects, then you might want to consider the simpler and possibly more efficient emplace interface:
map.emplace(count, str1.append(str2));
I want to use priority_queue like this:
priority_queue< pair< int, int> ,int ,cmp >
The comparision should be based on the int value in non-decreasing order.
Example:
((2,5),1),((2,5),2),((2,5),3)
Read the template parameters of std::priority_queue again. The second parameter is the underlying container. You can't use an int.
What you seem to be asking is how to store a pair and an int in a priority queue and sort by the int. Well, you've already figured out how to store a pair of ints. Simply expand that idea and store a pairof a pair and int. That's a naïve solution though. Instead, I recommend using a struct with the pair and the int as members so that you can give them descriptive names. Consider using a struct for the pair of ints too. Then simply use a compare functor which compares the third int only in the order of your choosing ignoring the pair.
priority_queue accepts only "one element" by saying one element I mean only a single element of arbitrary type. For having a pair, and int and another component in the priority queue you need to bring all of them as one meaning you need to be build a struct which will hold them. Then you have to use the bool operator < to tell the compiler how to compare the elements of your type .
bool operator < ( const structName& left, const structName& right)
{
return left.number < right. number;
}
this means that the comparison must be done with the member named number.
What is the difference between the following two lines?
map<int, float> map_data;
map<const int, float> map_data;
int and const int are two distinct types.
std::map<int, float> and std::map<const int, float> are, similarly, different types.
The difference between std::map<const int, float> and std::map<int, float> is, to a degree, analogous to the difference between, say, std::map<int, float> and std::map<std::string, float>; you get a fresh map type for each.
In the non-const case, the internal key type is still non-const int:
std::map<const int, float>::key_type => const int
std::map<int, float>::key_type => int
However, map keys are semantically immutable, and all map operations that allow direct access to keys (for example, dereferencing iterators, which yields value_type) does constify the key_type:
std::map<const int, float>::value_type => std::pair<const int, float>
std::map<int, float>::value_type => std::pair<const int, float>
So the difference may be largely invisible to you in every way that matters, if your implementation allows it.
That's not always the case, though: the standard officially requires your key type to be copyable and moveable, and some implementations re-use map nodes; under those implementations, attempting to use a const key simply won't work.
The key is already const, so it is redundant to write const in this case. Once an element is entered, its key cannot be changed.
Edit:
As mentioned in the comments, there is difference between the two lines. For example, if you write a function that accepts map<const int, int>, you can't pass to it map<int, int> since they're different types.
But note that although they are different types, they behave the same since the key in a map is a const anyway...
So in conclusion.. The only difference is that they are two different types, you shouldn't care about anything else.
The difference is that the second variant will set the key type for the map as const int. From the "modifiability" point of view this is redundant, since the map already stores its keys as const objects.
However, this can also lead to unexpected and non-obvious differences in the behavior of these two maps. In C++ a template specialization written for type T is different from specialization written for type const T. That means the above two versions of the map might end up using different specializations of various "satellite" templates that depend on the key type. One example is the key comparator predicate. The first one will use std::less<int> while the second one will use std::less<const int>. By exploiting this difference you can easily make these maps to sort their elements in different order.
Issues like that are more obvious with the new C++11 containers like std::unordered_map. std::unordered_map<const int, int> will not even compile, since it will attempt to use a std::hash<const int> specialization for hashing the keys. Such specialization does not exist in the standard library.
const can't be altered once set. And yes as per docs & other answer you should remember that key is const already.
Link: http://www.cplusplus.com/reference/map/map/
Link: http://en.cppreference.com/w/cpp/container/map
While the behaviour of your application will typically be the same, it makes a difference to some compilers you might use. The more specific example of what brought me to this page in the first place:
Explicitly specifying a map as map<const key, value> builds successfully with the gnu toolkit;
However it crashes a Studio12 Solaris x86 build.
map<key, value> builds successfully on both. Behaviour of the application is unchanged.
Const keys can be helpful if the keys are pointers. Using const keys won't let you modify the pointed object when accessing the keys, consider this:
#include <map>
#include <string>
int glob = 10;
int main() {
std::map<const int*, std::string> constKeyMap { { &glob, "foo"} };
std::map<int*, std::string> keyMap { { &glob, "bar" } };
for(const auto& kv : keyMap) { *(kv.first) = 20; }; // glob = 20
for(const auto& kv : constKeyMap) { *(kv.first) = 20; }; // COMPILE ERROR
return 0;
}
const refers to a constant, that, once defined, can't be altered then... non const key is subjected to change... or cant even change, it's just that "no change" is guaranteed in const (once defined), and "change" may or may not occur in non const stuff.
I currently have an array of pair<double, int> which I sort using a simple custom comparator function e.g.
// compare by first
int sort_index_lcomparator(const pair<double, int>& a, const pair<double, int>& b) {
return a.first < b.first;
}
// then sort simply like
pair<double, int> arr[size];
std::sort(arr, arr + size, sort_index_lcomparator);
I'm actually interested in the index order and not in the sorted doubles. My problem is that I would like to change away from this structure and have instead a struct of two arrays rather than an array of a struct i.e. I would like to optimize for locality and auto-vectorization but in this case I need an overloaded swap which is attached to a type specifically. I guess I would need something along the lines of redefining swap for the double type and keep both arrays in sync in such custom swap. Is there a way to "override" swap in such a manner within a limited scope?
I have one proposal for you: make the index array the one you sort and keep the values as global array. From then on: sort based on comparator that accepts indices, but actually compares based on the values.
You should specialize std::sort using your custom "comparator".
template <class RandomAccessIterator, class Compare>
void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
By default sort uses a standard comparator which just compares the elements referenced by the given iterators.
Using the custom Compare you may override this. Note that it's not a function (in C++ generally you may not pass a function as a template parameter). It's a class. You pass an object of this class to sort, whereas this object should implement the following operator:
bool operator () (const Type1 &a, const Type2 &b);
So, you may invoke sort for array of your double's. Your comparator should have pointers to the beginning of both your arrays: double and int.
In case with arrays the iterator resolves into a pointer to an array element. Using the array starting address you may convert it into an index, and use it to access the second array.