1

I am using the following code for automatic vector/matrix template parameter deduction (I am particullarily interested in automatic deduction from passing initializer lists)

template<class T, size_t N0> Tensor( const T (&t)[N0] ) -> Tensor<T,N0>; template<class T, size_t N0, size_t N1> Tensor( const T (&t)[N0][N1] ) -> Tensor<T,N0,N1>; 

My question is, simply, if there exists a way to extend these 2 definitions to arbitrary dimensions using a parameter pack :

template<class T, size_t ... Ns> Tensor( ??? ) -> Tensor<T,Ns...>; 
14
  • Not in a oneliner. It'll have to be Tensor(const T &) -> SomeTemplate<T>;, where SomeTemplate would expand would analyze T (recursively) and return the correct tensor. Commented Sep 11 at 13:33
  • stackoverflow.com/questions/67012144 duplicate? Commented Sep 11 at 13:35
  • 1
    @cigien I saw that question already, but I don't believe it is a duplicate (?). Or maybe I misunderstood the other question (?). It seems to me that the answers to the other question only work for arrays of dimensions already known by the compiler, but in this case, I can pass initializer lists and have the dimensions correctly deduced. Commented Sep 11 at 13:38
  • not directly what you are looking for, though it might be useful input to look at std::mdspan. Commented Sep 11 at 13:39
  • @Xenos The top answer is exactly what I had in mind. Wdym by "arrays of dimensions already known by the compiler", the dimensions are always fixed at compile-time for arrays. Commented Sep 11 at 13:41

1 Answer 1

3

Here are some templates which you can use to convert multidimensional array type to your Tensor type.

#include <type_traits> #include <utility> template <typename T, std::size_t N> struct prepend_index_sequence; template <std::size_t N, std::size_t... Ms> struct prepend_index_sequence<std::index_sequence<Ms...>, N> { using type = std::index_sequence<N, Ms...>; }; template <typename T, std::size_t N> using prepend_index_sequence_t = typename prepend_index_sequence<T, N>::type; template <typename T> struct mdarray_traits { using value_type = T; using dimentions = std::index_sequence<>; }; template <typename T, std::size_t N> struct mdarray_traits<T[N]> { using value_type = typename mdarray_traits<T>::value_type; using dimentions = prepend_index_sequence_t<typename mdarray_traits<T>::dimentions, N>; }; template <template <typename T, std::size_t...> typename ApplyOn, typename T, typename Dim> struct apply_array_traits_on_helper; template <template <typename, std::size_t...> typename ApplyOn, typename T, std::size_t... Dim> struct apply_array_traits_on_helper<ApplyOn, T, std::index_sequence<Dim...>> { using type = ApplyOn<T, Dim...>; }; template <template <typename T, std::size_t...> typename ApplyOn, typename ArrT> using apply_array_traits_on_t = typename apply_array_traits_on_helper< ApplyOn, typename mdarray_traits<ArrT>::value_type, typename mdarray_traits<ArrT>::dimentions>::type; 

Here is code covered with tests (using static asserts).

You can use this to create template deduction guide for your tensor. It will go more or less like this:

template<class T> Tensor(T arr) -> apply_array_traits_on_t<Tensor, T>; 

But probably you need to create some concepts to limit this template to arrays only to avoid conflicts with other overloads.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for your answer and the extensive code. Sadly I'm guessing this doesn't solve the problem of brace-initializers.
For that you need pattern similar to std::to_array. Note this is problem of distinguishing array from initialization list.
Unfortunately clang does not allow deduction guides that are not of the form X(some argument list) -> X<some argument list>, so Tensor(T) -> apply_array_traits_on_t<Tensor, T> would not work: godbolt.org/z/b6Ej7esoE

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.