1

I am doing some very basic problems to get familiar with Template Metaprogramming. This one in particular is just to add up the values on the down-right diagonal of a square matrix (indexes of [0,0],[1,1], etc.). I have solved this in many ways with different constexpr functions, but I do not understand why one particular way fails. Code and error message below:

constexpr int DRsum(const int* starter, const size_t size, int itr = 0)
{
    if(itr==size-1)
    {
        return *starter;
    }
    size_t sum = 0;
    sum = *starter;
    sum += DRsum(starter+size+1, size, itr+1);
    return sum;
}

int main()
{
    static const size_t size = 3;

    static constexpr const int matrix[][size] = {
    {1,2,3},
    {4,5,6},
    {7,8,9}
    };

    static constexpr int const* baseptr = &matrix[0][0];

    constexpr int sum = DRsum(baseptr, size);
}

The error message is as follows:

main.cpp|69|  in constexpr expansion of 'DRsum((& matrix[0][0]), 3u, 0)'|
main.cpp|39|  in constexpr expansion of 'DRsum((starter + ((((sizetype)size) + 1u) * 4u)), 
    ((size_t)size), (itr + 1))'|
main.cpp|69|error: '* starter' is not a constant expression|

I am not sure why this is doing this, as I am new to Template Metaprogramming. I made a dummy function to test if the pointer dereference was the issue, and that worked out fine. My guess is that it might have to do with me passing in a pointer rather than a pointer to a constexpr pointer, but I'm not sure. Any help would be appreciated, Thanks.

Also, I have already solved this by means of just passing in the entire structure (just straight up a deep copy) but I would rather know how to pass things by shallow copy or pointer into constexpr functions. Thanks.

xskxzr
  • 12,442
  • 12
  • 37
  • 77
Saswat Mishra
  • 185
  • 1
  • 11
  • 1
    The pointer is not constant, what it points to is constant in your declaration, so there's one misconception. Secondly, you talk about template metaprogramming, but there is no template involved here!? – Ulrich Eckhardt Aug 11 '18 at 12:03
  • Even with the added const after the * in both the function argument list and the pointer declaration, it still gives me the error message "main.cpp|68|error: '*(const int*)starter' is not a constant expression|". Basically i redefined baseptr from static constexpr int const* to static constexpr int const* const (which I thought constexpr implied for a pointer anyway). – Saswat Mishra Aug 11 '18 at 12:17
  • @SaswatMishra Which compiler are you using? gcc is fine, except that you are accessing the array out of its bounds https://godbolt.org/g/4M2sG3 – vdavid Aug 11 '18 at 12:20
  • @vdavid Im using GCC 5.1.0, and I'm pretty sure the "out of bounds" error message is a compiler misinterpretation of some other error that I am making, since when I change the variable declaration at the bottom from "constexpr int sum" to "int sum" (making DRsum run at runtime), everything works fine and I get the correct values. The function logic (as far as index access) is fine, my compiler just throws a fit about starter not being a constant expression. – Saswat Mishra Aug 11 '18 at 12:48
  • There is no templates in the question so I removed template-related tags. If you disagree, feel free to roll back. – xskxzr Aug 11 '18 at 12:58

1 Answers1

0

A 2D array (matrix) cannot be treated as a 1D array, so starter+size+1 results in undefined behavior. Usually undefined behavior is undefined so the program may work as expected, but when an undefined behavior happens within a structure that requires a constant expression, the program becomes ill-formed thus the compiler emits an error.

I don't think there is a simple fix because there is no well-defined way to access the whole 2D array through starter (even with std::launder), unless you change the signature of DRsum. For example, you can write DRsum as follows:

template <size_t size>
constexpr int DRsum(const int (*starter)[size], int itr = 0)
{
    if (itr == size - 1)
    {
        return (*starter)[itr];
    }
    size_t sum = 0;
    sum = (*starter)[itr];
    sum += DRsum(starter + 1, itr + 1);
    return sum;
}

then call it like constexpr int sum = DRsum(matrix);.

xskxzr
  • 12,442
  • 12
  • 37
  • 77