I want to form a struct from const parameters passed to the function. As the parameters are const, i guess the struct has to be const too. However, it does not work with pointers.
The following code compiles (MinGW 4.9.2 32bit)
struct structType_t {
int b;
};
void func1(const int b) {
const structType_t s={b}; // invalid conversion from 'const int*' to 'int*' [-fpermissive]
// do something with s;
}
but with pointers it doesn't:
struct structType_t {
int* b;
};
void func1(const int* b) {
const structType_t s={b}; // invalid conversion from 'const int*' to 'int*' [-fpermissive]
// do something with s;
}
Why does the compiler try to cast away the const here?
So how can i use a const pointer to initialise a const structure?
If you change your struct to hold a const int* you can use it to store the const int* passed to the function, regardless of whether your s is const or not.
struct structType_t {
const int* b;
};
void func1(const int* b) {
const structType_t s={b};
// or
structType_t s2={b};
// do something with s or s2 ...
}
In the first case you are creating a copy of an int. Copy of const int does not have to be const so it works.
In the second case you are creating copy of a pointer to const int and assigning it to a pointer to an int - this is not allowed and that's why it does not compile.
Related
This question already has answers here:
Binding a const pointer reference to a non-const pointer
(2 answers)
Closed 11 months ago.
before writing, I'm not good at english. So maybe there are many awkward sentence.
void Func1(const int* _i) { };
void Func2(const int& _j) { };
void Func3(const int* (&_k)) { };
int main()
{
int iNum = 1;
int* pInt = new int(1);
Func1(pInt); // works;
Func2(iNum); //works
Func3(pInt); // error
}
I use Visual Studio and error message said
"Cannot convert argument 1 from 'int *' to 'const int *&'"
I know it cant convert because of '&'. _i equals pInt so it may change dereference.
But i used const. so i think it will work but const keyword doesnt work.
why const keyword doesnt work unlike other cases? ex)Func1,Func2
Func1(pInt); // works; int* could convert to const int* implicitly
Func2(iNum); //works; int could be bound to const int&
Func3(pInt); // error;
pInt is a int*, when being passed to Func3 which expects a reference to const int*, then it would be converted to const int*, which is a temporary and can't be bound to lvalue-reference to non-const like const int* & (lvalue-reference to non-const pointer to const int).
If you change the parameter type of Func3 to int* &, then no conversion is required, pInt could be bound directly. Or change to const int* const & (lvalue-reference to const pointer to const int) or const int* && (rvalue-reference) which could bind to temporary.
Here is my code :
#include <iostream>
template<typename B>
class test{
public:
B* t;
test(const B& init){
}
};
void funct(const int*& test){
}
int main(int argc, char** argv) {
test<int*> t(new int(2)); // works fine
funct(new int(2)); //error
return 0;
}
I am trying to emulate what's happening on my templated class, but somehow i get errors. I believe that const B& init with B as int* will be const int*& init. Adding const allowed it to accept temporary "new"s. I made a non-templated function to test it and it has this header, void funct(const int*& test). It is just the same as above but how come it wont take new int(2) ?
const int*& means "reference to pointer to const int. You need the const to apply to the pointer, not to the int:
void funct(int* const& test){}
This is what the template version does. T is a pointer to int, so T& is really a reference to pointer to int. The template does not perform a textual substitution of T for int*. It substitutes the type. You'd get the same if you used typedef int* X and const X&.
Considering the following code :
#include <iostream>
#include <vector>
template<typename Type> class MyClass
{
public:
MyClass(Type* ptr) : _ptr{ptr}, _val{*ptr} {;}
inline Type*& getptr() {return _ptr;}
inline Type*& getptrc() const {return _ptr;}
inline Type& getval() {return _val;}
inline Type& getvalc() const {return _val;}
protected:
Type* _ptr;
Type _val;
};
int main()
{
std::vector<double> v = {0, 1, 2};
MyClass<const double> x(&v[0]);
x.getval();
x.getvalc(); // <- OK
x.getptr();
x.getptrc(); // <- ERROR : "invalid initialization of reference of type 'const double*&' from expression of type 'const double* const'"
return 0;
}
GCC produce an error for the getptrc function invalid initialization of reference of type 'const double*&' from expression of type 'const double* const'. But the function getvalc compiles well. I do not understand the difference between getvalc and getptrc that is at the origin of the error.
What is the cause of the error and why I can't put a const for a function that returns a reference to a pointer ?
const double*& is a reference to a pointer to a const double.
const double* const is a const pointer to a const double.
This means that you have to return a constant pointer.
inline Type* const & getptrc() const {return _ptr;}
const on methods means that you will not modify the data member. To fullfill that contract, you have to return a constant pointer because otherwise, you could modify the data member _ptr. However, in your other case with getvalc, you already have fullfilled that contract by returning a const double.
In MyClass<const double>, the name Type refers to const double. So the member function getvalc(), which returns a Type&, is fine: it returns a const double&, and _val cannot be modified through that reference.
There's another layer of indirection for Type*&; although Type is const double, the pointer that points to it is modifiable; that's why the compiler is complaining: _ptr is const inside the const member function, but the function attempts to return it as a modifiable pointer.
the below code doesn't compile
void aaa(const int **a) {
}
int *a[] = {new int[2]};
aaa(a);
I got "cannot convert parameter 1 from 'int [1]' to 'const int *" in VS2010 and similar error in gcc
when I change my declaration to:
int const *a[] = {new int[2]};
or
const int *a[] = {new int[2]};
it compiles, but I don't understand why it doesn't accept a non const variable declaration
The type of a is int*[]; the type you want is int const**.
int*[] converts to int**, but this will not convert implicitly to
int const**. Consider the following code to understand why:
static int const ci = 42;
void aaa( int const** out )
{
*out = &ci;
}
int
main()
{
int* pa;
aaa( &pa ); // NOT LEGAL, because...
*pa = 0; // would now change ci
std::cout << ci << std::endl;
return 0;
}
As you can see, allowing this conversion would break const without
requiring a cast.
Depending on what you are doing, you might want to use:
void aaa( int const* const* out );
The implicit conversion of int** to int const *const * is legal.
(Otherwise, you'll need a const_cast somewhere, to tell the compiler
that you know what you're doing, and that it isn't really a problem.)
The function aaa expects a pointer-to-pointer-to-constant-int.
Your variable a is a pointer-to-pointer-to-int.
It is an error to assign the latter to the former.
both int const *a[] and const int *a[] is actually the same thing, matching the signature of aaa. If you tried int * const a[], that would be a different type (pointer-to-constant-pointer-to-int) and you would trigger the type error again.
If you want your function aaa to take a constant-pointer-to-pointer-to-int, you need to write aaa(int ** const a), but having a const-ness on parameter values has actually no effect on what you can call with.
Edit: "But isn't constness added implicitly - done with an implicit cast? (Which is the actual question)"
Constness can be implicitly added to the value you are passing, e.g.
void aaa(const int a) {}
int b=5;
aaa(b);
... or one level pointer
void aaa(const int* a) {}
int *b=new int;
aaa(b);
... but cannot be added deeper. For example this is invalid:
void aaa(const int** a) {}
int* b=new int;
int** c=&b;
aaa(c);
I think James Kanze explains it much better in his answer.
I want to have a pointer to a constant, and pass its address to a function that will increment it.
int f1(const int **ptr) {
int n = **ptr; //use pointer
(*ptr)++; //increment pointer
return n;
}
void foo(const int *data) {
const int *p = data;
const int n = f1(&p); //error: invalid conversion from ‘const int**’ to ‘int**’
//error: initializing argument 1 of ‘int LevelLoader::readWord(byte**)’
}
How do I declare the pointers?
Try
int f1(const int *& ptr) {
int n = *ptr;
++ptr;
return n;
}
void foo(const int *data) {
const int *p = data;
const int n = f1(p);
}
instead.
The error message indicates that LevelLoader::readWord doesn't take a const byte**.
This:
const int *data;
is a pointer to a constant integer. That means that you are not allowed to change the data pointed to by data. You can read and copy the data, but you can't do:
(*data) = 5;
That's illegal in C++ because it was declared const int *.
If you take the address of a const int *, you get a const int **, which is a pointer to a pointer to a constant integer. So you still cannot change the integer. Any attempt to do so will cause the compiler to complain.
If you want to be able to change the integer, then foo and f1 should not take const int * values. They should take int * values.
I don't want to modify the constant. I want to modify the pointer to it (p in foo())
So, you're given a pointer. And you want to increment the pointer. So just do so:
void foo(const int *data) {
const int *p = data;
data++;
}
You have incremented the pointer. This will not affect the caller to foo, as the pointer itself is copied by value.
Check again, this code is correct. It shouldn't generate the errors you claim.
EDIT: You fixed the void problem so answer amended accordingly.