First off I would like to mention that this works with MSVC but not with clang. I am using Clang with c++11.
I have a function pointer:
typedef void (*Log) (const char* title, const char* msg, const char* file, int line);
I have this struct:
struct FunctionList
{
protected:
static const int kNbrMax = 32;
FunctionList();
bool Add(const void* f);
bool Remove(const void* f);
const void* m_functions[kNbrMax];
};
And this class:
template<typename T>
struct MessageFunctionList
: public FunctionList
{
public:
MessageFunctionList(T defaultFunction)
{
Add(defaultFunction);
}
void Call(const char* title,const char* cause,const char* file,int line)
{
for (unsigned long i = 0;i < m_nbrUsed;++i)
{
reinterpret_cast<T>(m_functions[i])(title,cause,file,line);
}
}
}
I am creating it like so:
static void DefaultLogMessageFunction(const char* title,const char* msg,const char* file,int line)
{
}
MessageFunctionList<Log> functionList(DefaultLogMessageFunction)
But I get the compile time error:
reinterpret_cast from 'const void ' to 'void ()(const char *, const
char *, const char *, int)' casts away qualifiers for line:
reinterpret_cast(m_functions[i])(title,cause,file,line);
So as far as I understand I am trying to cast my const list of functions to a non const value. That is not allowed which makes sense. So I tried the following:
const void* funcPtr = m_functions[i];
const T call = reinterpret_cast<const T>(funcPtr);
call(title, cause, file, line);
But that does not work either.
This works:
void* funcPtr = const_cast<void*>(m_functions[i]);
T call = reinterpret_cast<T>(funcPtr);
call(title,cause,file,line);
But I would like to avoid using a const cast. What am I doing wrong? How can I call this const function? Or is it simply not allowed because it does not know if the function being called is a const function or not? Or perhaps it is because my static function is not a member of a class so it can not be declared const?
You are storing the function pointers as const void*:
const void* m_functions[kNbrMax];
And you are trying to cast them to T and call it using reinterpret_cast:
reinterpret_cast<T>(m_functions[i])(title,cause,file,line);
However, reinterpret_cast cannot remove const qualifier from a type, therefore, you should first remove the const using const_cast:
reinterpret_cast<T>(const_cast<void*>(m_functions[i]))(title,cause,file,line);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
However, please note that const_cast engenders undefined behavior and is unsafe. So is calling a function pointer returned from reinterpret_cast if the original pointer was not actually a T.
Edit:
You can call a const qualified function pointer, however, then the reinterpret_cast should contain the const qualifier:
reinterpret_cast<const T>(m_functions[i])(title,cause,file,line);
Related
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 define some generic pointer (? but not a void pointer) using this code:
class A
{
template<typename T>
using ptr = T*;
using ubyte = uint8_t;
public:
const ptr<ubyte>
getColor1() const {
return &colors[0];
}
const ubyte*
getColor2() const {
return &colors[0];
}
private:
ubyte colors[4];
};
However, the getColor1() won't compile.
What's the difference between this two functions ?
gcc says:
error: invalid conversion from 'const ubyte* {aka const unsigned char*}' to 'A::ptr<unsigned char> {aka unsigned char*}' [-fpermissive]|
Update:
The deleted answer says I could do this:
//option 1
template<typename T>
using const_ptr = const T*;
or
//option 2
const ptr<ubyte>
getColor() //remove cv-qualifier
{
return &colors[0];
}
From option1,
It constructs now to const const, what does const const means?
From option2,
Why just removing cv-qualifier makes this compile?
const ptr<ubyte> is the same as const (ubyte *) which is not the same as const ubyte (*). You are trying to return a const pointer to a non-const char, which the compiler won't allow because you've declared the function itself const; all members become const because of that. The compiler won't automatically cast const to non-const without a const_cast.
To make the difference clearer, the first is a const pointer to a non-const char and the second is a non-const pointer to a const char. The first allows the pointed-to characters to change, even though the pointer itself can't change. Since the function was marked as const it can't return anything that would allow its members to be modified.
The best way to fix it:
ptr<const ubyte>
getColor1() const {
return &colors[0];
}
Because of the syntax of your ptr template, const ptr<ubyte> first makes it a ubyte*, then applies the const, resulting in a ubyte * const, a constant pointer to an ubyte.
In order to return a pointer to a const ubyte, you need to feed a const ubyte into your pointer template, so constness is applied first:
ptr<const ubyte>
1) "what does const const means?"
const T* const pT = new T;
Means const pointer pT - you cannot assign pT to another object;
to a const object of type T - you cannot change the object which is pointed by pT.
2) "Why just removing cv-qualifier makes this compile?"
getColor1()
method without const modifier can modify the object. It now returns A::ubyte* which can be converted to a const type such as declared as return type: A::ubyte* const (const ptr< ubyte > )
I have some problem removing constness using const_cast. Error msg says "Conversion is a valid standard conversion....."
What is the nature of this problem? Why should I use C-style cast instead?
"error C2440: 'const_cast' : cannot convert from 'const size_t' to 'size_t'"
"Conversion is a valid standard conversion, which can be performed implicitly or by use of static_cast, C-style cast or function-style cast"
template<typename T>
const IFixedMemory* FixedMemoryPkt<T>::operator=(const IFixedMemory* srcObj)
{
// doesn't remove constness this way. why?
const_cast<char*> (this->m_Address) = (char*)srcObj->GetAddress();
// compile this way, but maybe(?) undefined behaviour
// const_cast<char*&> (this->m_Address) = (char*)srcObj->GetAddress();
// doesn't doesn't work too
const_cast<size_t> (this->m_Size) = (size_t)(srcObj->GetSize());
// const_cast<size_t> (this->m_Size) = 0;
return this;
}
template<typename T>
class FixedMemoryPkt : public IFixedMemory
{
private:
const size_t m_Size;
const char* m_Address;
}
class IFixedMemory
{
public:
virtual const char* GetAddress() const = 0;
virtual size_t GetSize() const = 0;
}
const_cast is used to convert from pointers or references to const objects, to their non-const equivalents. However, you can't use them to modify the object they refer to if the object itself is const. There is no valid way to modify m_Size; if you want to modify it, then don't declare it const.
You do not need a cast to assign to the pointer, since the pointer itself is not const:
this->m_Memory = srcObj->GetAddress();
If you did want the pointer itself to be const, then the const would come after the *:
char * const m_Address;
and, as with the const size_t, you wouldn't be able to reassign it.
As the error says, you can convert a const value into a non-const temporary copy of that value without a cast; but you couldn't assign to that temporary.
You're attempting to cast the size_t thing to an r-value, and you can't assign to an r-value.
I have to say that casting away the constness of your size_t member is pretty evil. That's what mutable is for. And AFAICS your 1st const cast does nothing useful.
Works this way now...
template<typename T>
const IFixedMemory* FixedMemoryPkt<T>::operator=(const IFixedMemory* srcObj)
{
this->m_Address = srcObj->GetAddress();
this->m_Size = srcObj->GetSize();
return this;
}
template<typename T>
class FixedMemoryPkt : public IFixedMemory
{
private:
const char* m_Address;
size_t m_Size;
};
I am receiving this error invalid conversion from ‘const char*’ to ‘char*’ from this code:
// in account.h
struct account {
char* get_name ( ) const;
char name[MAX_NAME_SIZE+1];
};
//in account.cxx
char* account::get_name ( ) const
{
return name;
}
Can someone please help me?
The return type should be const char* as well:
const char* get_name ( ) const;
It is because in a const member function, this pointer becomes a const, as a result of which every member of the class becomes const, which means name which is declared as char[N], becomes const char[N] in a const member function. const char[N] can converts into only const char*, hence you need to make the return type const char*.
You're returning a non const pointer. You want to return a const char:
// in account.h
const char* get_name ( ) const;
//in account.cxx
const char* account::get_name ( ) const
{
return name;
}
The reason is that your method is declared const, but the pointer you're returning could be used to modify name, which would be a violation of the method's const promise.
Since get_name is a const method, all the members of the implicit object are const in the context of that method. By returning name as a char *, you are dropping the const qualifier from name. You could return const char *.
I have a struct with a const pointer to an object. It is const so that the pointer won't change, I do not wish to have the object constant. I'd like to call a non-constant function in that object, thus receiving the following error:
error C2662:
'my_namespace::MyClass::myFunc' :
cannot convert 'this' pointer from
'const my_namespace::MyClass' to
'my_namespace::MyClass &'
Conversion loses qualifiers
struct MyStruct
{
MyStruct( const MyClass* init_my_class_ptr );
const MyClass* my_class_ptr;
};
...
struct_instance.my_class_ptr->aNonConstFunc();
...
Assume I can't make aNonConstFunc() const.
Change your struct to:
struct MyStruct
{
MyStruct( const MyClass* init_my_class_ptr );
MyClass* const my_class_ptr;
};
That will make the pointer, instead of the pointee, const.
More elaborate explanation (also see Wikipedia): the const keyword is applied to whatever comes before it, except in case there's nothing in front, then it applies to what comes after it. So:
const A * object; // Non-const pointer to const A
A const * object; // Non-const pointer to const A
A * const object; // Const pointer to non-const A
const A * const object; // Const pointer to const A
A const * const object; // Const pointer to const A
Now, this is just personal preference, but this is why I always put const after whatever is supposed to be const. When applied everywhere in your code, this makes it very easy to figure out what exactly is supposed to be const. No need to go decipher if the const applies to statement before or after it.
Change const MyClass* my_class_ptr; to MyClass* const my_class_ptr;
const MyClass* my_class_ptr; declares my_class_ptr to be a pointer to a const MyClass object.
MyClass* const my_class_ptr declares my_class_ptr to be a constant pointer to a MyClass
object and that's what you need.
The use of const.
The general rule is that const is applied to the object on the left of const. Unless const is the left most part of the declaration then it is applied to the right.
// Thus these two are equivalent.
const char* data1; // 'pointer to' const char (const applied to right because it has nothing on left)
char const* data2; // 'pointer to' const char
I prefer putting const on right as I can then consistently use the rule of reading types from right to left.
char const* data3; // 'pointer to' const char (reading right to left)
char* const data4; // const 'pointer to' char (reading right to left)
This is a style pref and lots of people prefer the const on the far left (and are smart enough to auto read the declaration in their head :-).
BUT Where it becomes important is when you add typedefs into the mix:
typedef is NOT a textual substitution, if defines a type alias (or synonym).
typedef char* CHARP;
const char* data5a; // 'pointer to' const char
const CHARP data5b; // const ''pointer to' char' ***(NOT THE SAME AS above)***
char* const data6a; // const 'pointer to' char
CHARP const data6b; // const ''pointer to' char'
So when you start using typedefs the meaning can change (if you put const on the far left) and just do a textual cut and paste when creating your typedefs. But th
Finally to answer the question.
You want a const pointer in your structure. To do this make sure the const is on the right side of the '*' symbol.
struct MyStruct
{
MyStruct(MyClass* const init_my_class_ptr)
: my_class_ptr(init_my_class_ptr)
{}
MyClass* const my_class_ptr; // const pointer to MyClass
};