STL Map with custom compare function object - c++

I want to use the STL's Map container to lookup a pointer by using binary data as a key so I wrote this custom function object:
struct my_cmp
{
bool operator() (unsigned char * const &a, unsigned char * const &b)
{
return (memcmp(a,b,4)<0) ? true : false;
}
};
And using it like this:
map<unsigned char *, void *, my_cmp> mymap;
This compiles and seems to work, but I'm not sure what an "unsigned char * const &" type is and why it didn't work with just "unsigned char *"?

You need to provide a comparator that guarantees non-modifying of the passed values, hence the const (note that it applies to the pointer not the char). As for the reference operator (&), you don't need it -- it's optional. This will also compile:
struct my_cmp
{
bool operator() (unsigned char * const a, unsigned char * const b)
{
return memcmp(a,b,4) < 0;
}
};

It works for me with just unsigned char *.

Related

reason for pointer to a const pointer when using static_cast

I have tried to solve an exercise from a book but I failed on the static_cast. I used the qsort Method from cstdlib. I have to cast the parameters of my function to a C-String (const char*). But I always get the error message: stattic_cast from type 'const void*' to type 'const char**' casts away qualifiers.
int scmp(const void *s1, const void *s2) {
const char *c1 = (static_cast<const char**>(s1));
const char *c2 = (static_cast<const char**>(s2));
....
}
const char *sfield[] = {"one", "two", "three", "four", "five"};
qsort(sfield, 10, 4, scmp);
The solution is as follows
const char *c1 = *(static_cast<const char* const*>(s1));
What is the reason for the last const and where does it come from? Why I have to cast to a pointer to a constant pointer to char const?
It comes from the origin pointer. static_cast may not discard the const qualifier. So you can only cast void const* to a T const*.
Now, it just so happens that your T is a char const*. You were probably led astray by the leading const in your original code. It does not apply where one may think it applied.
The qsort comparator parameters are pointers to const versions of the elements being compared. In your example the elements being compared are const char *, so a pointer to const of that is const char * const *. Hence the correct version of the code:
int scmp(const void *s1, const void *s2)
{
auto pc1 = static_cast<const char * const *>(s1);
auto pc2 = static_cast<const char * const *>(s2);
char const *c1 = *pc1;
char const *c2 = *pc2;
return strcmp(c1, c2); // or whatever
}
You can do away with pc1, pc2 and apply * operator to the result of the cast if you like .
Perhaps you mistakenly assumed the arguments were the elements being compared, when in fact they are pointers to the elements being compared .
If it is still not clear then maybe it would help to use a symbolic name for the element type:
using ELEMENT_T = const char *;
int scmp(void const *s1, void const *s2)
{
auto pc1 = static_cast<ELEMENT_T const *>(s1);
auto pc2 = static_cast<ELEMENT_T const *>(s2);
ELEMENT_T c1 = *pc1;
ELEMENT_T c2 = *pc2;
return strcmp(c1, c2); // or whatever
}
The same pattern would work for elements that are not pointers (e.g. integer elements).

C++ template type and type of template

What is the type of T if I write something like that:
template<typename T>
class AClass{
private:
T member;
public:
AClass(const T& value = T()) : member(value) {}
};
int main(){
const char* n = "Hello";
AClass<char*> a(n);
return 0;
}
Does T refers to a char or a pointer over a char?
Thanks for your answers
Facts:
T is char * in your example
The example won't compile
Think about your constructor:
AClass(const T& value = T())
What you want is a pointer to const char, that is const char *.
In your constructor you are saying that T is const, thus you are asking for a const pointer to char, that is char * const.
They are actually two different beasts and the compiler complains about the lack of a const (let me say) in the right place in your constructor. That's because a conversion from const char * to char * is not allowed.
Assuming you meant to write
AClass<char*> a('n');
T is a char* (address), but 'n' would resolve to simply char. I don't believe it would compile.

C++ Pointer to const array of const pointers

I've created a const array of const pointers like so:
const char* const sessionList[] = {
dataTable0,
dataTable1,
dataTable2,
dataTable3
};
What is the correct syntax for a regular non-const pointer to this array? I thought it would be const char**, but the compiler thinks otherwise.
If you actually need a pointer to an array, as your title suggests, then this is the syntax:
const char* const (*ptr)[4] = &sessionList;
const char* const sessionList[] = { ... };
is better written as:
char const* const sessionList[] = { ... };
Type of sessionList[0] is char const* const.
Hence, type of &sessionList[0] is char const* const*.
You can use:
char const* const* ptr = &sessionList[0];
or
char const* const* ptr = sessionList;
That declares a pointer to the elements of sessionList. If you want to declare a pointer to the entire array, it needs to be:
char const* const (*ptr)[4] = &sessionList;
The same type as you declared for the array elements, with an extra * added:
const char* const *

operator[] overload to accept char * for subscript

I have following code:
class IList{
public:
virtual const Pair *get(const char *key) const = 0;
inline const Pair *operator[](const char *key) const;
};
inline const Pair *IROList::operator[](const char *key) const{
return get(key);
}
code compiles ok, but when I try to use it:
IList *list = (IList *) SomeFactory();
Pair *p;
p = list["3 city"];
I got:
test_list.cc:47:19: error: invalid types ‘IList*[const char [7]]’ for array subscript
p = list["3 city"];
^
I can understand that array subscript is int or char,
but then how std::map is doing char* / strings ?
If your list is a pointer as well you can't use [] operator in the way you did. That's because list["3 city"] is equivalent to list.operator[]("3 city"). If you provide pointer, you'd have to use list->operator[]("3 city") or - what is more readable - (*list)["3 city"]. Of course, you can also make your list a reference and use normally:
auto& listRef = *list;
p = listRef["3 city"];
It seems list is a pointer to IList object. So you should try:
p = (*list)["3 city"];

Using a custom comparator for std::map on IBM i-Series

I'm trying to use a std::map where the keys are c-style strings rather than std::strings but am having problems getting it to compile on an IBM iSeries targetting v7r1m0
I'd like to use c-style strings because using the Performance Explorer (PEX) it appears that the creation of lots of temporary strings for the purpose of map lookups is very expensive.
To do this I have used a custom comparator but when compiling on the iSeries I get an error:
"/QIBM/include/t/xtree.t", line 457.30: CZP0218(30) The call does not
match any parameter list for "const mycompany::myapp::cmp_str::operator()".
"/QIBM/include/t/xtree.t", line 457.21: CZP1289(0) The implicit object
parameter of type "mycompany::myapp::cmp_str &" cannot be initialized with an
implied argument of type "const mycompany::myapp::cmp_str".
My comparator is defined as:
struct cmp_str
{
bool operator()(char const *a, char const *b)
{
return std::strcmp(a, b) < 0;
}
};
and used in a map :
class LocalSchema : public RecordSchema
{
public:
int Operation;
//map<string, int> FieldLookup;
map<char *, int, cmp_str> FieldLookup;
};
Am I doing something stupid?
EDIT:
changing to
std::map<char const*, int, cmp_str>
gives the same error. Looking in to the job log further I see that this error was produced while processing the following function:
inline int VxSubfile::IndexOfFieldInSchema(char * columnName)
{
std::map<char const*, int, cmp_str>::iterator iter = _fieldLookup.find(columnName);
if(iter == _fieldLookup.end())
{
return -1;
}
else{
jdebug("Returning index : %d", iter->second);
return iter->second;
}
}
Change
map<char *, int, cmp_str>
to
std::map<char const*, int, cmp_str>
that is, with std::, and with const.
Edit: Also make the comparison member function const, i.e.
struct cmp_str
{
bool operator()(char const *a, char const *b) const
{
return std::strcmp(a, b) < 0;
}
};
Note 1: IBM's C++ compilers are infamous for being non-conforming in subtle ways, so you may still run into problems.
Note 2: You need to ensure that the strings outlive the map. E.g. you can use a vector<unique_ptr<char const[]>> as owner for the strings, allowing you to clean up.