1

I am trying to call a templated function from my main. I previously used this sort of syntax and it worked as shown here:

#include <iostream>

using namespace std;

// One argument in template
template<int size> 

void print(char matrix[][size]) {
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            cout << matrix[i][j];
        }
        cout << endl;
    }

    return;
}

// MAIN
int main() {
    constexpr int n = 3;
    char matrix[n][n] = {'a', 'b', 'c',
                         'h', 'i', 'd', 
                         'g', 'f', 'e'};

    print<n>(matrix); // Calling function like this

    return 0;
}

I am trying to apply this same method here in main using a multi-parameter template but it does not work. I get the error: No matching function for call to 'setRowZero'. I don't quite understand why it does not match as I follow the same structure above. It's just one more parameter!

#include <iostream>

using namespace std;

template<int num_rows, int num_cols>

// Set this entire row to 0
void setRowZero(int matrix[num_rows][num_cols], int row, int cols) {
    for (int i = 0; i < cols; i++) {
        matrix[row][i] = 0;
    }

    return;
}

int main() {
    // Matrix to be changed
    int matrix[3][4] = {1, 1, 1, 1,
                        1, 0, 1, 1,
                        1, 1, 0, 1};

    // Get row and cols
    int num_rows = sizeof(matrix)/sizeof(matrix[0]);
    int num_cols = sizeof(matrix[0])/sizeof(int);

    // Record the position of the 0s
    for (int i = 0; i < num_rows; i++) { // rows
        for (int j = 0; j < num_cols; j++) { // cols
            if (matrix[i][j] == 0) {
                rows[i] = 0;
                cols[j] = 0;
            }
        }
    }

    // Set to 0's
    for (int i = 0; i < num_rows; i++) {
        if (rows[i] == 0) {
            setRowZero<num_rows, num_cols>(matrix, i, num_cols);
        }
    }

    return 0;
}
0

2 Answers 2

3
// Set this entire row to 0
template<int num_rows, int num_cols>
void setRowZero(int (&matrix)[num_rows][num_cols], int row) {
  for (int i = 0; i < num_cols; i++) {
    matrix[row][i] = 0;
  }
}

and at call site:

setRowZero(matrix, i);

array arguments are not arrays due to C compatibility issues in C++; they "decay" to pointers.

References to arrays remain references to arrays.

This is why std::array was invented; it behaves less pathologically.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. That compiled. But I don't understand why I couldn't call it like so: setRowZero<num_rows, num_cols>(matrix, i).
@JessicaWang because num_rows and num_cols are runtime constants but not compile-time constants and compile-time constants are required for non-type (int) template parameters
1

First, rows and cols variables weren't defined, so I made some bogus ones (they will crash if you actually run it) because that's not the core part of your question (they are commented as "this is bad")

The problem is that you cannot have runtime-defined variables passed to a template. The compiler must know the values at compile time, so I changed them to be constexpr and that's what solves your main problem you were asking about.

https://godbolt.org/g/yihHNH

#include <iostream>

using namespace std;

template<int num_rows, int num_cols>
void setRowZero(int matrix[num_rows][num_cols], int row, int cols) {
    for (int i = 0; i < cols; i++) {
        matrix[row][i] = 0;
    }

    return;
}

int main() {
    int * rows; // this is bad
    int * cols; // this is bad
    // Matrix to be changed
    int matrix[3][4] = {1, 1, 1, 1,
                        1, 0, 1, 1,
                        1, 1, 0, 1};

    // Get row and cols
    constexpr int num_rows = sizeof(matrix)/sizeof(matrix[0]);
    constexpr int num_cols = sizeof(matrix[0])/sizeof(int);

    // Record the position of the 0s
    for (int i = 0; i < num_rows; i++) { // rows
        for (int j = 0; j < num_cols; j++) { // cols
            if (matrix[i][j] == 0) {
                rows[i] = 0;
                cols[j] = 0;
            }
        }
    }

    // Set to 0's
    for (int i = 0; i < num_rows; i++) {
        if (rows[i] == 0) {
            setRowZero<num_rows, num_cols>(matrix, i, num_cols);
        }
    }

    return 0;
}

As the other answer showed, you can have the compiler deduce the correct values for num_rows and num_cols if you don't specify them. It does that from the type of the variable being used at the call site and the dimensions of the type of the variable being passed in is also a compile-time constant.

1 Comment

I am late but thank you! Your explanation makes a lot of sense. Thanks for your patience.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.