Reputation: 583
My goal is to make this template work:
template <size_t... Ns>
struct mult
{
using cross = ?; // variadic size_t
static_assert(sizeof...(cross) + 1 == sizeof...(Ns), "");
};
So I can use it like this:
mult<2,3,5>::cross // 6,15 // because 2*3=6, 3*5=15
mult<3,5,7,11>::cross // 15,35,77 // because 3*5=15, 5*7=35, 7*11=77
Because I need to make this:
// tuple of arrays
std::tuple<std::array<size_t, mult<Ns...>::cross>...> cross_arrays;
Upvotes: 3
Views: 93
Reputation: 21160
If you want compile time computation, write constexpr
functions
template<typename... SizeT>
constexpr auto cross(size_t x, SizeT... xs)
{
std::array tmp = {x, xs...};
std::array ret = {xs...};
for(size_t i = 0; i < ret.size(); i++)
ret[i] *= tmp[i];
return ret;
}
template<size_t... xs, size_t... Is>
auto cross_tuple_fn(std::index_sequence<Is...>)
{
constexpr auto dims = cross(xs...);
return std::tuple<std::array<size_t, dims[Is]>...>{};
}
template<size_t... xs>
auto cross_tuple_fn()
{
return cross_tuple_fn<xs...>(std::make_index_sequence<sizeof...(xs) - 1>{});
}
template<size_t... xs>
using cross_tuple_t = decltype(cross_tuple_fn<xs...>());
They're easier to read, write and looks more or less the same as normal functions.
Use as
cross_tuple_t<Ns...> cross_arrays;
Upvotes: 2
Reputation: 66210
Not exactly as you asked...
For the cross
type I suppose you can use a standard std::index_sequence
.
To construct the correct sequence, I see a simple (?) recursive solution, based on an mult_helper
helper struct.
#include <utility>
#include <iostream>
template <typename, std::size_t ...>
struct mult_helper;
template <std::size_t A0, std::size_t A1, std::size_t ... As,
std::size_t ... Ns>
struct mult_helper<std::index_sequence<A0, A1, As...>, Ns...>
: public mult_helper<std::index_sequence<A1, As...>, Ns..., A0*A1>
{ };
template <std::size_t A0, std::size_t ... Ns>
struct mult_helper<std::index_sequence<A0>, Ns...>
{ using type = std::index_sequence<Ns...>; };
template <std::size_t... Ns>
struct mult
{ using cross = typename mult_helper<std::index_sequence<Ns...>>::type; };
int main ()
{
using T1 = mult<3u, 5u, 7u, 11u>::cross;
using T2 = std::index_sequence<15u, 35u, 77u>;
static_assert( std::is_same_v<T1, T2>, "!" );
}
Upvotes: 0
Reputation: 118352
Here's a solution that uses static_assert
not only to prove the order of the cross-product, but the entire cross product, explicitly.
#include <type_traits>
#include <utility>
#include <cstddef>
template<size_t ...Ns> struct indices;
template<typename, typename> struct add_indices;
template<size_t ...N1, size_t ...N2>
struct add_indices<indices<N1...>, indices<N2...>> {
typedef indices<N1..., N2...> equals;
};
template<size_t ...Ns> struct cross_impl;
template<size_t N1, size_t N2> struct cross_impl<N1, N2> {
typedef indices<N1 * N2> result;
};
template<size_t N1, size_t N2, size_t N3, size_t ...Ns>
struct cross_impl<N1, N2, N3, Ns...> {
typedef typename add_indices< indices<N1 * N2>,
typename cross_impl<N2, N3, Ns...>::result
>::equals result;
};
template<size_t ...Ns>
struct mult
{
using cross=typename cross_impl<Ns...>::result;
};
int main() {
static_assert(std::is_same<typename mult<2,3,5>::cross,
indices<6,15>>::value);
static_assert(std::is_same<typename mult<3,5,7,11>::cross,
indices<15,35,77>>::value);
return 0;
}
Upvotes: 3