0

My following code is used to check if an element exists in an array of the same type:

#include <iostream>
#include <vector>
using namespace std;

template <class T>
bool IsIn (T a, T B[]) {
  bool result = false;
  int _size = sizeof(B)/sizeof(B[0]);
  for(int i = 0; i < _size; i++)
    if (a == B[i])
      result = true;
  return result;
}

int main () {
  
  int arr1 [] = { 10, 20, 30 };
  bool ee1 = IsIn(10, arr1);
  cout << "ee1 = " << ee1 << endl;
  
  return 0;
}

I run it here using the C++ option, and get the following warnings:

main.cpp: In instantiation of ‘bool IsIn(T, T*) [with T = int]’:
main.cpp:19:27:   required from here
main.cpp:9:15: warning: ‘sizeof’ on array function parameter ‘B’ will return size of ‘int*’ [-Wsizeof-array-argument]
9 |   int _size = sizeof(B)/sizeof(B[0]);
  |               ^~~~~~~~~
main.cpp:7:19: note: declared here
7 | bool IsIn (T a, T B[]) {
  |                 ~~^~~

What have I done wrong? I don't quite get the meaning of these messages. Thank you in advance!

CaTx
  • 1,421
  • 4
  • 21
  • 42
  • It depends. You can pass `std::vector` (if size is not known at compile time), `std::array` if size is known at compile time, you can pass C-style array by reference or you can pass size as additional argument to the function. It all depends on why you decided to use C-style arrays in the first place. – Yksisarvinen Jul 11 '22 at 12:08
  • Is there any way to avoid passing the size of the array into the function? – CaTx Jul 11 '22 at 12:09
  • 5
    `template bool IsIn (T a, T (&B)[N])` – NathanOliver Jul 11 '22 at 12:10
  • `T B[]` as function parameter losses all the information that it was ever an array. It's precisely the same as `T B*` parameter. This is called [decay to pointer](https://stackoverflow.com/questions/1461432/what-is-array-to-pointer-decay/1461466#1461466). You can pass the array by reference (see NathanOliver's comment) if you want compiler to handle passing the size over. – Yksisarvinen Jul 11 '22 at 12:11
  • @NathanOliver, I am a beginner and don't quite follow what you wrote. Can you clarify by writing the whole code? – CaTx Jul 11 '22 at 12:12
  • 2
    @NathanOliver gave the same answer I was preparing here : https://godbolt.org/z/8W5nazn68 (with some other code style review comments) – Pepijn Kramer Jul 11 '22 at 12:14
  • @CaTx You just need to replace the start of the function with what I put. You can also get rid of `int _size = sizeof(B)/sizeof(B[0]);` in your function since the `N` parameter will be the array size. – NathanOliver Jul 11 '22 at 12:14
  • @PepijnKramer, it works beautifully. Can you explain to me what magic happens? I am not following what goes on in that code. – CaTx Jul 11 '22 at 12:17
  • 1
    @CaTx Sure I can :) The template is matched against the size of your array at compile time and it will generate a function that matches exactly with that size (the N in the template). https://en.cppreference.com/w/cpp/language/range-for will use the begin and end of the array to loop over all values for you. Since the loop should only observe the values it uses const T, since we don't want to copy T we use a reference &. (oversimplified a reference is like a pointer that cannot be null) – Pepijn Kramer Jul 11 '22 at 12:18
  • 1
    I assume you took a datastructures class that used C++ to teach you how to write them. However that kind of C++ is not the kind of C++ that is supposed to be written. Learn about stl datatypes (std::vector,std::array,std::stack,std::list etc.), about references, constness and giving variables very clear names. https://www.learncpp.com/ while not perfect is a pretty decent start. After that have a look at https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines – Pepijn Kramer Jul 11 '22 at 12:23
  • @PepijnKramer, I have seen lots of const being used around. I am dazzled by it. Could you please tell me why it is necessary, and where to start reading? – CaTx Jul 11 '22 at 12:27
  • Every C++ textbook explains what `const` is. Is there something in yours' that's unclear to you? – Sam Varshavchik Jul 11 '22 at 12:28
  • Also, where is the size of the array computed to be used in your code? I am not seeing that done anywhere. – CaTx Jul 11 '22 at 12:29
  • By the way, I would like to thank everyone for all the help so far. It has been eye-opening. – CaTx Jul 11 '22 at 12:30
  • 1
    Loosely explained : The compiler knows the size of the array from your initialization `int arr1[]={10,20,30}` it can see it has 3 elements. Then it tries to find a match with the template where it finds argument `const T(&values)[N]` and deduces N must be 3. It then creates a function specifically for array size 3 and uses that. – Pepijn Kramer Jul 11 '22 at 12:35
  • const near an argument means that code may use the variable it but not modify it. At the end of a member function of a class it means the function may not modify any member variables of that class (but only observe/use them). And it is very useful in avoiding bugs – Pepijn Kramer Jul 11 '22 at 12:36
  • Are you saying if I later use this function template with a different size, another function with that data type and size will be created? On the other hand, the same template using vector does not need an extra function of the same data type created? – CaTx Jul 11 '22 at 12:38
  • @NathanOliver why do we pass by const reference and not by value? Is there any pros to it? – CaTx Jul 11 '22 at 12:42
  • 1
    @CaTx if you don't pass the array by reference, then it decays into a pointer and you loose the size information. When you pass the array by reference you get to "keep" the size information. – NathanOliver Jul 11 '22 at 12:44

0 Answers0