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"];
Related
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).
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.
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 *
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 *.
I have a class which hold an array "float ** table". Now I want to have member function to return it, but don't want it to be modified outside of the class. So I did this:
class sometable
{
public:
...
void updateTable(......);
float **getTable() const {return table;}
private:
...
float **table;
}
This compiles OK when I call getTable with a constant object. Now I tried to
make it safer by declaring getTable as "const float **getTable()". I got
the following compilation error:
Error:
Cannot return float**const from a function that should return const float**.
Why? How can I avoid table to be modified out side of the class?
Declare your method like this:
float const* const* getTable() const {return table;}
or
const float* const* getTable() const {return table;}
if you prefer.
You can't assign a float** to a float const** because it would allows to modify a const object:
float const pi = 3.141592693;
float* ptr;
float const** p = &ptr; // example of assigning a float** to a float const**, you can't do that
*p = π // in fact assigning &pi to ptr
*ptr = 3; // PI Indiana Bill?
C and C++ rules differ about what is allowed.
C++ rule is that when you add a const before a star, you have to add a const before each following one.
C rule is that you can only add a const before the last star.
In both languages, you can remove a const only before the last star.
You could declare your method as
const float * const * const getTable() const {return table;}
but even this (the outermost const - next to the function name) would not prevent the client to try to delete it.
You could return reference instead, but the best would be to use an std::vector for table and return const ref to it - unless using a C style array is a must
Though you can clearly type the syntax just like that, I find it much more readable to define some typedefs for multiple-dimension arrays.
struct M {
typedef double* t_array;
typedef const double t_carray;
typedef t_array* t_matrix;
typedef const t_carray* t_cmatrix;
t_matrix values_;
t_cmatrix values() const { return values_; }
t_matrix values() { return values_; }
};