2

I have the following base code:

Base Code

int main()
{
  int i = 1;

  const int* p = &i;
  int* q = &i;

  test_ptr(p);
  test_ptr(q);
}

Can anyone explain why the first and third example work with the above base code, but the second one doesn't?

Example Implementation test_ptr()

Example 1 works. This works because function with pointer to const int will also accept a pointer to non-const int (but not the other way around)

void test_ptr(const int* p)  // pointer to const int
{

}

Example 2 doesn't work. I don't really understand why. It is still a pointer to const int, but passed as a reference. This doesn't align with my understanding about how references work. It fails when I pass a non-const pointer to the function.

void test_ptr(const int*& p)  // reference to pointer to const int
{

}

Example 3 works again and I am completely lost. So if case 2 does not work, why does it work again if I express the int* as a typedef?

typedef int* int_ptr;

void test_ptr(const int_ptr& p)  // like case 2 but int* expressed as typedef
{

}

This also happens when I use pointer-to-pointer instead of reference-to-pointer.

Edit: Example 3 needs a different main function to make use of the typedef:

int main()
{
  int i = 1;

  const int_ptr p = &i;  // use typedef here
  int_ptr q = &i;  // use typedef here

  test_ptr(p);
  test_ptr(q);
}
TonySalimi
  • 8,257
  • 4
  • 33
  • 62
Cerno
  • 751
  • 4
  • 14
  • What do you mean example 2 does not work? It can work with right type of calling. See [a live demo](https://gcc.godbolt.org/z/E_H2fa). – TonySalimi Apr 28 '20 at 11:44
  • `void test_ptr(int const* const& p)` would be the correct signature for 2. The pointer needs to be `const` too. – Ted Lyngmo Apr 28 '20 at 11:46
  • .... and 3 does not work when you pass `p` to it since `int_ptr` is non-const. `const int_ptr&` means `int* const&` not `int const*&`. – Ted Lyngmo Apr 28 '20 at 11:53
  • Does [this](https://stackoverflow.com/a/36302190/7582247) answer your question? – Ted Lyngmo Apr 28 '20 at 12:12
  • Hm. That linked question doesn’t get to the *real* problem. The issue is that test_fun might modify q and assign an actually const int* into it. Then main has a const int* where it thinks it has an int* and can break things. – HTNW Apr 28 '20 at 12:38
  • @TedLyngmo Example 3 works if you modify the main function, sorry for the confusion, I made an edit to the post. The question you linked seems to duplicate parts of mine, I'll check the answers. Could you elaborate on why the typedef works different than my intuition? This is interesting. Maybe formulate it as an answer? – Cerno Apr 28 '20 at 12:39
  • @gupta Yes, I know that I can make it work by calling it with a pointer to const, but I would like to know why I can call example 1 with a pointer to non-const but not example 2 – Cerno Apr 28 '20 at 12:47
  • I'll give it a try even though I'm hesitating because I know the words of the standard poorly. – Ted Lyngmo Apr 28 '20 at 12:59
  • 1
    @TedLyngmo Nevermind that. Anyone with a better proposal can throw their suggestion in the ring. Better an imperfect answer than none at all. Thanks for your help. – Cerno Apr 28 '20 at 14:44

1 Answers1

1

Example 2:

void test_ptr(const int*& p);

This works for const int* but not int* because the conversion from int* to a const int* implies a temporary and binding to a temporary has to be done using a const& for life extension to kick in.

Example 3 (when using the first main version):

typedef int* int_ptr; // or: using int_ptr = int*;

void test_ptr(const int_ptr& p);

This is the same as both of these:

void test_ptr(int_ptr const& p);
void test_ptr(int* const& p);

const is applied to the new type from right to left so it's not the int that is const, it's the pointer. The function will therefore accept int*, but not const int* since the function is allowed to change the int:s according to its signature.

The function that would accept both int* and const int* should have one of these equivalent signatures:

void test_ptr(const int* const& p);
void test_ptr(int const* const& p);

Disclaimer: I'm very unsure about the wording used in this answer

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • 1
    That seems to work. I chose to get rid of the typedef since it was not what I wanted to express anyway. Moving the const from before the int_ptr to behind the int_ptr clarified why this was the case. I went with the extra const at the end of your answer, which did the trick for me. – Cerno Apr 28 '20 at 14:17
  • @Cerno Great! I was trying to find the correct passages in the standard to make the answer better by using the words of the standard - but when it comes to this it refers back and forth between different chapters so I found it hard to make it clearer. – Ted Lyngmo Apr 28 '20 at 14:21