1

I am writing a small Tensor class, that should look like this:

using namespace std; // for simplicity
template<typename T, size_t N>
class Tensor {
    size_t rank_;
    array<int, N> size_;
    vector<T> data;
public:
    template<typename... Args>
    Tensor(Args... args) : rank_{ N }, size_{args...}, data((... * args), T{}) {
        static_assert(sizeof...(Args) == N, "Wrong number of indicies");
        static_assert(conjunction_v<is_integral<Args>...>, "Not an integer_type");
...

        

For the constructor I want to do a few compile-time checks to prevent errors:

  1. After the initialization I check whether the correct numbers of arguments (N) have been passed to the constructor (is there a way to enforce this check before the constructor initializes the data?

  2. I check whether the caller passes only integral data types to the constructor.

  3. I want to check whether all the passed values are larger than zero. I don't know how to implement the third condition. I tried something like

    static_assert(conjunction_v<bool_constant<(args > 0)>...>, "Index must be larger than zero!");

This code does not compile. I think, that static_assert might not even be usable here, because the actual sizes of the dimensions may be known at runtime rather than compile time. What is the best way to implement such a check on a parameter pack (at compile time when possible, else on runtime)? I initialize the array<int,N> size_ with the parameter pack, so in the constructor I could iterate over the array and check for the correct range. But is this the cleanest solution?

Urwald
  • 343
  • 1
  • 10
  • 1
    I would just write a loop and check all of the values. function parameters can't be used in `static_assert` so you ether need to recurse or iterate over the pack/array to check the values. – NathanOliver Apr 18 '22 at 12:43
  • 1
    1) `assert((args > 0) && ...);` 2) *the actual sizes of the dimensions may be known at runtime rather than compile time* - No, that's never the case. `Args...` is always a compile-time thing. – Evg Apr 18 '22 at 12:49
  • @Evg Does this mean that whenever I want to create a `Tensor` object the parameters I have to pass to the constructor must be `constexpr` ? – Urwald Apr 18 '22 at 13:07
  • 1
    Checking for negative values will have to be at run time. Or if you really want the values known at compile time, you could have `template class Tensor;`, so that `Tensor` and `Tensor` are two different types. – aschepler Apr 18 '22 at 13:15
  • 1
    @Evg I think here "the actual sizes of the dimensions" is the values of the arguments matching `Args... args`, not the count or `sizeof` anything. – aschepler Apr 18 '22 at 13:20
  • 1
    No, why? A compiler will deduce their types and will instantiate a template with those types. Inside a function, arguments are never `constexpr`, no matter whether they are `constexpr` on the call site or not. – Evg Apr 18 '22 at 13:20
  • @Evg As @aschepler has pointed out I was indeed referring to the sizes of the individual dimensions (as determined by the values I pass to the constructor and not to the rank of the Tensor (which is determined by the number of arguments and must be known at compile time). Thank you very much for your explanation on the `constexpr` ! – Urwald Apr 18 '22 at 13:27

0 Answers0