c++c++11templatesstdinitializerlist

How a function template can deduce the number of times an initializer_list is nested?


I have a function template that takes an arbitrarily nested list and returns an array:

#include <array>
#include <initializer_list>

template<size_t N, typename List>
std::array<size_t,N> some_function (const List& list)
{
    // N is the number of times the list is nested.
    std::array<size_t,N> arr;
    return arr;
}

When I use this function for some nested std::initializer_list, like this:

int main () {
    using List = std::initializer_list<std::initializer_list<double>>;
    List list = {{1.,2.,3.},{4.,5.,6.}};

    std::array<size_t,2> arr;
    arr = some_function (list);
    return 0;
}

I receive the error that type N can not be deduced

couldn't deduce template parameter ā€˜Nā€™

Question


Solution

  • You can write two overloaded constexpr function templates to calculate the nested times, with the help of std::enable_if and SFINAE.

    // types have not member type value_type
    template <typename T, typename = void>
    struct has_value_type: std::false_type {};
    // types have member type value_type
    template <typename T>
    struct has_value_type<T, std::void_t<typename T::value_type>> : std::true_type {};
    
    // return nested times as 0 for types without member type value_type
    template<typename T>
    constexpr std::enable_if_t<!has_value_type<T>::value, size_t> get_nested_times() {
        return 0;
    }
    // return nested times as 1 plus times got on the nested type recursively
    template<typename T>
    constexpr std::enable_if_t<has_value_type<T>::value, size_t> get_nested_times() {
        return 1 + get_nested_times<typename T::value_type>();
    }
    

    then you can get the nested times at compile-time as

    template<typename List>
    auto some_function (const List& list)
    {
        // N is the number of times the list is nested.
        constexpr auto N = get_nested_times<List>();
        std::array<size_t, N> arr;
        return arr;
    }
    

    LIVE