5

I have a type declared as:

using Buffer = std::unique_ptr<std::array<uint8_t, N>>;

I also have a template function declared as:

template<typename Buffer>
bool temp_func()
{
    // do something
}

and I'm calling temp_func with type Buffer:

temp_func<Buffer>();

now, inside temp_func I want to get the size of the type Buffer without creating an instance of this type.

what I need is something similar to std::tuple_size<Buffer>::value except I can't call std::tuple_size on unique_ptr, only directly on std::array.

I can use C++11 only. How can I do it?

Brian61354270
  • 8,690
  • 4
  • 21
  • 43
אנונימי
  • 304
  • 2
  • 7
  • 1
    Whats is `N` in your declaration? – tkausl Feb 25 '23 at 23:09
  • 3
    `Buffer::element_type` would be your array type. And `std::tuple_size` would work on that type. – Drew Dormann Feb 25 '23 at 23:10
  • 1
    "_I want to get the size of the type Buffer_": What size exactly do you want to have? The size of `Buffer` (i.e. `std::unique_ptr>`), the size of `std::array` or the value `N`? These are all different things and your question seems to imply all three at different places. – user17732522 Feb 25 '23 at 23:10
  • There's probably something convoluted you could do with `sizeof` and [std::declval](https://en.cppreference.com/w/cpp/utility/declval) but it might be better if you define an alias for the intermediate type `std::array`, and then have `using Buffer = std::unique_ptr;` – Nathan Pierson Feb 25 '23 at 23:10
  • 1
    @tkausl `array::size()` is nonstatic, so it requires an instance. Instead, you can use `std::tuple_size::value`. – Raymond Chen Feb 25 '23 at 23:12
  • `N` is hard coded unsigned value: `std::size_t N = 50000U`. I want to get back `N` – אנונימי Feb 26 '23 at 08:39

2 Answers2

10

Use std::unique_ptr::element_type to access the contained array type, then apply std::tuple_size as you normally would.

#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <tuple>

constexpr std::size_t N{10};

using Buffer = std::unique_ptr<std::array<std::uint8_t, N>>;

static_assert(std::tuple_size<Buffer::element_type>::value == N, "error");

Try it on godbolt.

In C++17 or above, you can substitute std::tuple_size<T>::value with std::tuple_size_v<T> for added conciseness:

#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <tuple>

constexpr std::size_t N{10};

using Buffer = std::unique_ptr<std::array<std::uint8_t, N>>;

static_assert(std::tuple_size_v<Buffer::element_type> == N);
Brian61354270
  • 8,690
  • 4
  • 21
  • 43
  • what if mu Buffer is not declaring directly as `using Buffer = std::unique_ptr>;`. instead, I have a template class `BufferContatiner` that wrap a container of the template type. and Buffer declared as `using Buffer = std::unique_ptr>>;`. – אנונימי Feb 26 '23 at 08:37
  • 1
    @אנונימי `BufferContainer` would need to expose it's underlying array type. E.g. define a member type like `BufferContainer::array_type`. Then just proceed in the same way: `std::tuple_size::value` – Brian61354270 Feb 26 '23 at 13:03
  • Or better yet, expose `N` directly from `BufferContainer` – Brian61354270 Feb 26 '23 at 13:20
  • worked for me, except I had to add `typename`: std::tuple_size::value`. can you explain to me why? – אנונימי Feb 26 '23 at 13:30
  • 1
    @אנונימי `typename` is needed for [dependent types](https://en.cppreference.com/w/cpp/language/dependent_name). Whether that expression has dependent types depends on where the names are coming from. For example, if your [use case looks like this](https://godbolt.org/z/TnhcPrYMn), `typename` isn't required. – Brian61354270 Feb 26 '23 at 16:42
3

You can use partial specialization to define a trait that gets N from Buffer. I assume the element type is always uint8_t. Then this works in C++11:

#include <iostream>
#include <memory>
#include <array>


template <typename T> struct size_of_unique_uint8_t_array;

template <size_t N>
struct size_of_unique_uint8_t_array<std::unique_ptr<std::array<uint8_t,N>>> {
    static constexpr size_t value = N;
};


int main()
{
    using Buffer = std::unique_ptr<std::array<uint8_t, 42>>;
    std::cout << size_of_unique_uint8_t_array<Buffer>::value;
}

Live Demo

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185