1

I wanted to do a simple thing with templates and got surprised how not simple it is. I have got :

  • An array which size is 9, let's say type const int *

I want it to pass it as an argument for an object construction, like so:

const int * myArray[9];
//filling array;
ObectType<int*> myObject(&myArray[0]);

With object constructor here :

template<class T>
class ObjectType
{
public:
   ObjectType(const T * myArray) : myArrayMember(myArray) {};
   const T * myArrayMember;
}

But I get the following error :

error: invalid conversion from ‘const int**’ to ‘int* const*’ [-fpermissive]
   86 |     ObectType<int*> myObject(&myArray[0]);
      |                                 ^~~~~~~~
      |                                 |
      |                                 const int**

Shouldn't const T * be replaced by const int** ? I have tried to keep it simple, the real code is more complicated. Tell me if you need some information.

Bebel
  • 49
  • 6
  • You fell into a similar trap as the person who asked this https://stackoverflow.com/q/64893722/817643 – StoryTeller - Unslander Monica Dec 19 '20 at 20:46
  • 1
    Because my array contains pointer. And to pass an array that contains pointers as an argument, you need to have int** copiedArray = &realArray[0], where real array is declared like so : int * realArray[x]; – Bebel Dec 19 '20 at 20:47
  • The answer in the link you sent, StoryTeller, is way more complicated than the one I got. Thank you, though ! – Bebel Dec 19 '20 at 20:50
  • 1
    The answer your got falls short on describing the trap (although it does follow a better convention implicitly). There's a reason memes like "leading const is misleading" and "east const is best const" permeate. Do yourself a favor and adopt a convention that works along side human intuition when doing substitution.. – StoryTeller - Unslander Monica Dec 19 '20 at 20:53
  • @StoryTeller-UnslanderMonica That's a very good point. I should have made that explicit in the first place. I've edited the answer to address that aspect. – cigien Dec 20 '20 at 06:18

1 Answers1

2

When you create myObject you are specifying the template parameter T with the argument int*. When substituted into the constructor argument T const *, this gives int * const *, which is incorrect.

You need T to be int const *, and you need to provide the correct template argument:

ObjectType<int const *> myObject(&myArray[0]);

Or from C++17, you can let it be deduced:

ObjectType myObject(&myArray[0]);

As mentioned in a comment by StoryTeller-UnslanderMonica, it's worth pointing out that the explanation in this answer seems obvious because I have chosen to use the "east const" notation which I find much more preferable for a number of reasons. You can read this Q&A for more details.

In this case, the benefit of this notation is that understanding how template argument substitution works becomes easier, and the correct substitution becomes more obvious.

cigien
  • 57,834
  • 11
  • 73
  • 112