2

I have a class that stores an std::array.

The size of the array is evaluated in compile time, this is because the application runs on an embedded device so no dynamic allocations :(. The code looks something like this:

template<uint8_t size>
class A
{
    //some constructor
    A(...);
    std::array<int, size> what;
}
//Wanted use cases
A instance1({1,2,3});
//Unwanted use case
A<3> instance2({1,2,3});

I don't know how to construct the constructor that I want. I've tried for a week now dozens of designs and none got what I wanted. Here are the names of thing that I have tried:

  1. Template deduction guides - also templated versions, which I'm not sure if they are legal...
  2. std::initializer_list - the size of the list cannot be put in the template argument. At least not in a non-constexpr context.
  3. std::array
  4. plain old array
  5. using keyword - also templated.

Tl;Dr:

How to deduce a template parameter value signifying a size of an array type from the given array in the signature of the constructor function?

Waqar
  • 8,558
  • 4
  • 35
  • 43

2 Answers2

6

A small example using deduction guides:

template<uint8_t size>
class A
{
public:
    template <typename... Args>
    constexpr A(Args&&... args)
    : what { std::forward<decltype(args)>(args)... }
    {}
    constexpr size_t getSize() const { return what.size(); }
private:
    std::array<int, size> what;
};

//deduction guide
template <typename... Args> A(Args... args) -> A<sizeof...(args)>;

int main()
{
    //Wanted use cases
    A instance1 (1,2,3);
    static_assert (instance1.getSize() == 3);
    
    //or
    //A instance1 {1,2,3};
    return 0;
}
Waqar
  • 8,558
  • 4
  • 35
  • 43
2
#include <array>

template<class... U>
class A
{
    std::array<int,sizeof...(U)> what;
public:
    constexpr A(U&&... u) : what{std::forward<U>(u)...} { }
    constexpr std::size_t size() const { 
        return what.size();
    }
};

int main() {
    A a(1,2,3,4,5,6);
    static_assert(a.size() == 6);

    A b(1);
    static_assert(b.size() == 1);
    
    return 0;
}
Vasilij
  • 1,861
  • 1
  • 5
  • 9
  • 1
    Can you explain what is going on here? – Eyal Kamitchi Jul 29 '20 at 14:10
  • Since class A is based on the array (on logical level) the whole class is templated. The class has a constructor which takes any number of arguments of the same type. The constructor uses initializer list to initialize the array with perfect forwarding to avoid copying. To support different numbe of arguments we use variadic templates . To get the number of arguments we use sizeof...(U). constexpr are used to do everything at compile time and check with static_assert. – Vasilij Jul 29 '20 at 14:22
  • You can skip all the constexpr and play with the code here: https://godbolt.org/z/qPKEs8 – Vasilij Jul 29 '20 at 14:50