0

An example given for non-type template parameters is an array:

template <typename T, int size> // size is an integral non-type parameter
class StaticArray
{
private:
    // The non-type parameter controls the size of the array
    T m_array[size] {};
}

What are the options for handling negative values in the input? Using std::is_signed doesn't really apply - the template parameter is defined as signed, so the type would always be signed, whether or not the actual value provided is or not.

It looks like the implementation in std::array on my system sets the type to std::size_t, which isn't what I need in my use case. I'm hoping for something I can use with std::enable_if, where negative values are valid but have different method implementations.

I've tried the following, but that the compiler doesn't seem to be sure how to distinguish the '>' operator vs '>' as a template indication.

template<>
Iterator& operator++(std::enable_if_t<SIZE > 0>) { m_ptr++; return *this; }  
template<>
Iterator& operator++(std::enable_if_t<SIZE < 0>) { m_ptr--; return *this; }  

[edit] I was unaware of constexpr-if, which seems like a better approach but is C++17 (my original tag was C++11, but I've now added C++17).

The following is at least compiling and seems more readable than conditionally added methods, but I'm not sure if this is the recommended approach:

Iterator& operator++()
{
    if constexpr (SIZE > 0)
        m_ptr++;
    else if constexpr (SIZE < 0)
        m_ptr--;
    else
        static_assert(SIZE == 0, "SIZE cannot be zero.");
    return *this;
}

[edit2] The syntax for enable_if/enable_if_t is unclear to me for a non-type template parameter. Both fail to compile when adding parentheses around the conditional.

With enable_if_t I get

error: argument may not have 'void' type
Iterator& operator++(std::enable_if_t<(SIZE > 0)>) { m_ptr++; return *this; }
                                                 ^

With enable_if, I get

error: parameter of overloaded post-increment operator must have type 'int' (not 'std::enable_if<(2 > 0)>')
Iterator& operator++(std::enable_if<(SIZE > 0)>) { m_ptr++; return *this; }
                                               ^
Brett Stottlemyer
  • 2,734
  • 4
  • 26
  • 38
  • 1
    If you're getting an error, please include that message in the question. If there's no error, please include the behaviour of the code, and how it differs from what you expect. – cigien Aug 13 '22 at 17:33
  • 1
    Does this answer your question? [How to use > (greater-than) inside a template parameter and not get a parsing error?](https://stackoverflow.com/questions/33423702/how-to-use-greater-than-inside-a-template-parameter-and-not-get-a-parsing-er) – cigien Aug 13 '22 at 17:37
  • Thanks @cigien, that addresses a part of my question. I'm asking for the right approach, and getting my attempt to compile doesn't make it the right approach. That question _did_ teach me something I didn't know, which is appreciated. I'll edit my question. – Brett Stottlemyer Aug 13 '22 at 18:24
  • Why the votes to close? – Brett Stottlemyer Aug 13 '22 at 18:40
  • 1
    Why not just static_assert on `size > 0`? After all, `size` *cannot* change. It's a template parameter, and therefore is a constant expression. It's also not clear why you're focused on `operator++`, which again *cannot* change the size. – Nicol Bolas Aug 13 '22 at 19:10
  • @NicolBolas I'm trying to learn more about template programming and for my test use-case I'm trying to have different behavior for positive and negative values. The only case which doesn't make sense is zero. The idea is to have a class with an iterator that iterates forwards or backwards a set number of steps depending on the template parameter. This helps with searching for a known pattern in potentially corrupted data. – Brett Stottlemyer Aug 13 '22 at 19:37
  • @BrettStottlemyer: Your class declares an array with `size`. Arrays cannot have a size of 0 or of a negative number. So that's going to be a compile error *regardless* of what `operator++` eventually does. – Nicol Bolas Aug 13 '22 at 19:42
  • @NicolBolas Sure. My actual code is larger, with a complete Iterator struct with a class that takes a pointer. I tried to make a minimal example that demonstrated the question, which is specific to the handling of the non-type template parameter. Apologies if not including that detail impacted your understanding of the question. I didn't know what direction this question would go! – Brett Stottlemyer Aug 13 '22 at 19:48

1 Answers1

0

Here's an example to get you started:

template <typename T, int size> // size is an integral non-type parameter
class StaticArray
{
private:
    T m_array[size] {};

public:
    std::enable_if_t<(size > 0), Iterator&>
    operator++() { /* ... */ }
};
lorro
  • 10,687
  • 23
  • 36
  • Is the `Iterator &` supposed to be the return value for operator++ or part of the enable_if_t<>? If the latter, what is that doing? – Brett Stottlemyer Aug 13 '22 at 19:08
  • 1
    @BrettStottlemyer It's part of `enable_if_t<>`'s arguments; but `enable_if_t<>` is the expression deducing return type (when condition is true), so `Iterator&` is actually the return type _when_ this can be applied. – lorro Aug 13 '22 at 19:17
  • probably because size can never `<0` since it's array size. not my downvote though. – apple apple Aug 14 '22 at 16:41
  • @appleapple Size can be `0`, then `(size > 0) == false`. Also, this code is from OP - they clearly wanted a condition there. – lorro Aug 14 '22 at 16:46
  • @lorro no, 0-size array is not allowed. – apple apple Aug 14 '22 at 16:47
  • @appleapple `int size`, so technically it can be. It's not valid in generic C++ (in C99 it is valid), but most compilers support it. Even if it's not valid, it should be handled. Also, the idea is not to push whether it's `size == 0`, OP simply wanted a condition on a non-type parameter. If you look at OP's code, this condition is clearly there. – lorro Aug 14 '22 at 16:50
  • @lorro I'm not sure what your arguing, `size==0` is not valid, period. So the code is meaningless. – apple apple Aug 14 '22 at 16:52
  • @lorro I'm just tell you what may be the reason you got that downvote. let me say it again, it's not mine. – apple apple Aug 14 '22 at 16:54
  • @appleapple Understood, didn't mean to offend - just listing the reasons & logic behind it. – lorro Aug 14 '22 at 16:59