I have a funciton like
void foo(const char *&str)
{
cout<<str<<endl;
}
used like:
void main()
{
foo("hello");
char *h = "hello"
foo(h);
}
but both got an error
"can't convert from const char[] to const char *&"
if I change foo to void foo(const char *), there is no error can't I use const char *& as parameter
You got an error because the conversion is illegal. The reason
it is illegal is simple: it breaks const without requiring
a const_cast.
As an example of why it is forbidden, imagine that foo was:
void
foo( char const*& str )
{
str = "abc";
}
int
main()
{
char* h;
foo( h );
*h = '1';
}
If you're not going to modify str in foo, pass by value.
Pass by reference will works if you have char const* const&,
but there's no reason to use it here. It works because the
additional const means that you can bind a temporary to it (as
in the case of foo( "hello" ), where the argument is
a temporary resulting from the conversion of char const[6] to
char const*, and foo( h ) works, because the implicit const
conversions will work (in C++, but not in C!), as long as you
add const everywhere (and not just at one level).
Also, your code also uses a deprecated conversion to initialize
h. You should get a warning here. And void main is an
error, and shouldn't compile.
Edit:
Just to be clear, there's no problem with:
void f( char const*& str );
But you can only call it with an lvalue of type char const*;
anything else will either result in an illegal implicit const
conversion, or try to initialize a non-const reference with an
rvalue, which is illegal.
This will work
int main()
{
const char *h = "hello";
foo(h);
}
Related
I am learning C++. I am trying to pass a string to a function via const char* str. I understand the basic meaning of this passing.
In the function body, when I try char * ptrStr = str, I got error: cannot initialize a variable of type 'char *' with an lvalue of type 'const char *'. But when I try auto ptrStr = str, it works.
I have two questions here: (1) could you please help explain why the former fails while the latter works? (2) how to use smart pointers here?
#include<iostream>
#include<memory>
void func(const char* str){
char* ptrStr = str;
}
/*
void func(const char* str){
auto ptrStr = str;
}
*/
int main(){
func("5486321 ");
return 0;
}
How to convert char* to const char* in C++? Why program 1 is working but program 2 can't?
Prog 1 (working):
char *s = "test string";
const char *tmp = s;
printMe(tmp);
void printMe(const char *&buf) {
printf("Given Str = %s", buf);
}
Prog 2 (not working)
char *s = "test string";
printMe((const char *)s); // typecasting not working
void printMe(const char *&buf) {
printf("Given Str = %s", buf);
}
The error I receive:
x.cpp:10:15: warning: conversion from string literal to 'char *' is
deprecated [-Wc++11-compat-deprecated-writable-strings]
char *s = "test string";
^
x.cpp:12:5: error: no matching function for call to 'printMe'
printMe(s);
^~~~~~~
x.cpp:6:6: note: candidate function not viable: no known conversion
from 'char *' to 'const char *&' for 1st argument
void printMe(const char *&buf)
^
1 warning and 1 error generated.
Thanks.
printMe takes an lvalue reference to a mutable pointer to const char.
In your first example, tmp is an lvalue of type mutable pointer to const char, so a reference can be bound to it without issue.
In your second example, (const char*)s creates a temporary const char* object. Lvalue references to mutable objects can't bind to temporaries, so you get an error. If you change printMe to take a const char* const& then the call will succeed with or without the explicit cast.
void printMe(const char * const& buf) {
printf("Given Str = %s", buf);
}
int main() {
char s[] = "test string";
printMe(s);
}
Live on Coliru
Of course, if you don't want to alter the object (the pointer) passed into printMe, then there's no reason to use a reference at all. Just make it take a const char*:
void printMe(const char * buf) {
printf("Given Str = %s", buf);
}
int main() {
char s[] = "test string";
printMe(s);
}
Live on Coliru
In the end, this is the same reason something like this:
void doSomething(const std::string& s) {}
int main() {
doSomething("asdf");
}
works while this:
void doSomething(std::string& s) {}
int main() {
doSomething("asdf");
}
does not. A temporary object is created, and the reference to non-const object can't bind to the temporary.
It seems obvious that constexpr implies const and thus it is common to see:
constexpr int foo = 42; // no const here
However if you write:
constexpr char *const str = "foo";
Then GCC will spawn "warning: deprecated conversion from string constant to ‘char*’" if -Wwrite-string flag is passed.
Writing:
constexpr const char *const str = "foo";
solves the issue.
So are constexpr const and constexpr really the same?
The issue is that in a variable declaration, constexpr always applies the const-ness to the object declared; const on the other hand can apply to a different type, depending on the placement.
Thus
constexpr const int i = 3;
constexpr int i = 3;
are equivalent;
constexpr char* p = nullptr;
constexpr char* const p = nullptr;
are equivalent; both make p a const pointer to char.
constexpr const char* p = nullptr;
constexpr const char* const p = nullptr;
are equivalent. constexpr makes p a const pointer. The const in const char * makes p point to const char.
The error message you're seeing has nothing to do with the constexpr keyword per se.
A string literal like "foo", as in:
somefunction("foo");
The type of this string literal is const char *. The following statement:
char *const str = "foo";
This tries to assign a const char * value to a char * value. The resulting char * value is non-mutable, constant, but by that time the error already occured: an attempt to convert a const char * to a char *.
The constexpr keyword in your example is just a distraction, and has no bearing on the error.
No. To say they are the same means that there's no time that not using const would be valid without producing functionally identical code to a const version.
I find this useful in the creation of safe singletons. I haven't explored this fully, and would expect there are other valid uses for non-const constexpr.
As an example, here is code that requires non-const constexpr:
Start with a global definition of a variable:
int global_int_;
And now we can create a constexpr function that returns a reference to it:
constexpr int& get_global()
{
return global_int_;
}
Now we can use that reference somewhere else:
int main()
{
constexpr int& i{ get_global() };
// do stuff with i
return 0;
}
We can now use i as a non-const int. If const was implied, this would not be possible.
Since non-const constexpr is valid, if you are using a constexpr that needs to be const you will need to explicitly declare it.
I have a function:
void add(char const**);
And I invoke it as follow:
template<typename T>
void anotherAdd(T const& t) {
add(&t);
}
...
anotherAdd("some string");
As a result I get the error:
no known conversion for argument 1 from 'const char (*)[10]' to 'const char**'
Why the conversion can't be made?
Because I think the following is true:
"some string" <=> char const* =>
&"some string" <=> char const**
Arrays are not pointers.
This code expects a pointer to a pointer
void add(char const**);
The compiler is telling you that it can't produce a pointer to a pointer because your code has no pointer to point to. You're effectively trying to evaluate &"some string", which has no valid meaning.
This code will work, because it creates the missing char const* that you're trying to take the address of.
template<typename T>
void anotherAdd(T const& t) {
char const *pt = &t; // Now there's a pointer that you can take the address of.
add(&pt);
}
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.