Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Idiomatic way to get size_type from std::array or the like

Triggered by this question, I came up with code along the line of (it was boost::array in my answer, but the same applies for std::array):

template <std::array<char,1>::size_type size>
void DataTransform(std::array<char, size> data) {

}

And I am not happy at all with <std::array<char,1>::size_type. I have to instantiate with a certain size, to know the size_type. For std::array I could have used size_t, but then what about the general case? What if size_type is not size_t? Or even more general (ie not for std::array) what if size_type is different for different sizes (silly but possible)?

I know this question is rather academic and there are many ways to avoid this "problem" completely (eg I could have passed iterators). Anyhow, I wonder...

What is a clean way to determine the size_type for templates that need a size (of type size_type) to be instantiated?

More generally, the question could be formulated as: How can I get my hands on a templates typedef that may depend on a template parameter before actually instantiating the template.

like image 531
463035818_is_not_a_number Avatar asked Dec 08 '22 11:12

463035818_is_not_a_number


1 Answers

Here is a C++11 solution that takes the array undeduced, then extracts the involved types and size in defaulted template arguments and finally does an enable_if to check if we were indeed given a std::array:

#include <array>
#include <type_traits>

template<
    class TArray,
    class TSize = typename TArray::size_type,
    class TValue = typename TArray::value_type,
    TSize size = std::tuple_size<TArray>::value>
typename std::enable_if<std::is_same<std::array<TValue, size>, TArray>::value>::type
DataTransform(TArray data)
{
    // Enjoy!
}

https://godbolt.org/z/KMziYq

Doing all this via defaulted template arguments means that this is SFINAE-friendly (all the checks are done during substitution). But it's also quite a mouthful compared to the C++17 solution :)

I should mention though that std::tuple_size (which has basically the same problem as the original question) does flat out use std::size_t. That shouldn't really be a problem because std::size_t should be able to hold all relevant values and we still extract and provide the "correct" TSize above. But you can do all this without std::tuple_size by writing your own one that is given TSize and deduces only the size value:

template<class TValue, class TSize, class T>
struct MyTupleSize;

template<class TValue, class TSize, TSize size>
struct MyTupleSize<TValue, TSize, std::array<TValue, size>>
{
    static constexpr TSize value = size;
};

https://godbolt.org/z/zlseRm

like image 81
Max Langhof Avatar answered Dec 09 '22 23:12

Max Langhof