get the size of std::array inside unique_ptr without an instance in c++
Asked Answered
T

2

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?

Taka answered 25/2, 2023 at 23:6 Comment(6)
Whats is N in your declaration?Excitor
Buffer::element_type would be your array type. And std::tuple_size would work on that type.Tessie
"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<std::array<uint8_t, N>>), the size of std::array<uint8_t, N> or the value N? These are all different things and your question seems to imply all three at different places.Cryoscopy
There's probably something convoluted you could do with sizeof and std::declval but it might be better if you define an alias for the intermediate type std::array<uint8_t, N>, and then have using Buffer = std::unique_ptr<Intermediate_t>;Quin
@Excitor array::size() is nonstatic, so it requires an instance. Instead, you can use std::tuple_size<typename Buffer::element_type>::value.Willner
N is hard coded unsigned value: std::size_t N = 50000U. I want to get back NInfringement
P
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);
Pyrognostics answered 25/2, 2023 at 23:16 Comment(5)
what if mu Buffer is not declaring directly as using Buffer = std::unique_ptr<std::array<std::uint8_t, N>>;. instead, I have a template class BufferContatiner that wrap a container of the template type. and Buffer declared as using Buffer = std::unique_ptr<BufferContainer<rstd::array<std::uint8_t, N>>>;.Infringement
@Taka 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<Buffer::element_type::array_type>::valuePyrognostics
Or better yet, expose N directly from BufferContainerPyrognostics
worked for me, except I had to add typename: std::tuple_size<typename Buffer::element_type::array_type>::value`. can you explain to me why?Infringement
@Taka typename is needed for dependent types. Whether that expression has dependent types depends on where the names are coming from. For example, if your use case looks like this, typename isn't required.Pyrognostics
O
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

Overglaze answered 25/2, 2023 at 23:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.