Here is my solution using C ++ 11 variation patterns and package extensions.
My "foobar" compiles as a constexpr function, so I would say pretty efficiently: p
As for elegance, you can be a judge, but I think that is pretty good.
Basically, the idea is to replace the for loops with a functional way of programming iteration, where we are simply trying to explicitly create the set that we want to iterate over first. This code can then be generalized to arbitrary dimension in a simpler way.
The code is completely self-contained, with the exception of the <array> header.
It compiles for me in the C ++ 11 standard with gcc 4.8.2 and clang 3.6.
Note. If you want to use the same technique for code where dimensions are a run-time parameter, basically you would override the Cartesian_Product metafile below as a run-time function using something like std::vector<std::vector<size_t>> , You can then create your own set of iterations by taking the dim number of Cartesian products and going through it, using a single loop to populate the result.
#include <array> #include <iostream> ///////////////////////////////////////////// // The point class from problem statement ///////////////////////////////////////////// template <size_t dims> class Point { public: double data[dims]; }; // Some basic type list and meta function objects to work with // List of indices template<size_t... sl> struct StList { static constexpr size_t length = sizeof...(sl); }; // Metafunction to compute a volume template <typename T> struct Compute_Volume; template<size_t s> struct Compute_Volume<StList<s>> { static constexpr size_t value = s; }; template <size_t s1, size_t s2, size_t... sl> struct Compute_Volume<StList<s1, s2, sl...>> { static constexpr size_t value = s1 * Compute_Volume<StList<s2, sl...>>::value; }; // Concatenate template<typename TL, typename TR> struct Concat; template<size_t... SL, size_t... SR> struct Concat<StList<SL...>, StList<SR...>> { typedef StList<SL..., SR...> type; }; template<typename TL, typename TR> using Concat_t = typename Concat<TL, TR>::type; // Meta function to check if a typelist is component-wise less than another typelist // For testing purposes template <typename TL, typename TR> struct all_less_than; template <size_t l1, size_t... SL, size_t r1, size_t... SR> struct all_less_than<StList<l1, SL...>, StList<r1, SR...>> { static constexpr bool value = (l1 < r1) && all_less_than<StList<SL...>, StList<SR...>>::value; }; template<> struct all_less_than<StList<>, StList<>> { static constexpr bool value = true; }; ///////////////////////////////////////////////////////////////////////////// // constexpr template function for the point initializations you described ///////////////////////////////////////////////////////////////////////////// template <typename index, typename dims> struct point_maker; template <size_t... idx, size_t... dim> struct point_maker<StList<idx...>, StList<dim...>> { static_assert(sizeof...(idx) == sizeof...(dim), "misuse of 'point_maker' template, idx and dim must have same number of coordinates"); static_assert(all_less_than<StList<idx...>, StList<dim...>>::value, "misuse of 'point_maker' template, idx is out of bounds"); static constexpr Point<sizeof...(idx)> make_point() { return {{ ((idx + 0.5) / static_cast<double>(dim))... }}; } }; ////////////////////////////////////////////////////////////////////////////////////////// // Now we need to abstract the for loops. We need a little more infrastructure for this. ////////////////////////////////////////////////////////////////////////////////////////// // A basic typelist object template <typename... tl> struct TypeList { static constexpr size_t length = sizeof...(tl); }; // Specialization for the Concat metafunction template<typename... TL, typename... TR> struct Concat<TypeList<TL...>, TypeList<TR...>> { typedef TypeList<TL..., TR...> type; }; // Metafunction to compute the cartesian product of two lists of lists, and evaluate the `Concat` metafunction for each pair. template <typename S, typename T> struct Cartesian_Product; template <typename s1, typename s2, typename... sl, typename T> struct Cartesian_Product<TypeList<s1, s2, sl...>, T> { typedef Concat_t<typename Cartesian_Product<TypeList<s1>, T>::type, typename Cartesian_Product<TypeList<s2, sl...>, T>::type> type; }; template <typename s, typename t1, typename t2, typename... tl> struct Cartesian_Product<TypeList<s>, TypeList<t1, t2, tl...>> { typedef Concat_t<typename Cartesian_Product<TypeList<s>, TypeList<t1>>::type, typename Cartesian_Product<TypeList<s>, TypeList<t2, tl...>>::type> type; }; template <typename s, typename t> struct Cartesian_Product<TypeList<s>, TypeList<t>> { typedef TypeList<Concat_t<s, t>> type; }; template <typename S, typename T> using Cartesian_Product_t = typename Cartesian_Product<S, T>::type; // Some unit tests for the above :) static_assert( std::is_same<Cartesian_Product_t<TypeList<StList<1>, StList<2>>, TypeList<StList<3>, StList<4>>>, TypeList<StList<1,3>, StList<1,4>, StList<2,3>, StList<2,4>>>::value , "cartesian product not working"); static_assert( std::is_same<Cartesian_Product_t<TypeList<StList<1,5>, StList<2>>, TypeList<StList<3>, StList<4>>>, TypeList<StList<1,5,3>, StList<1,5,4>, StList<2,3>, StList<2,4>>>::value , "cartesian product not working"); static_assert( std::is_same<Cartesian_Product_t<TypeList<StList<1,5>, StList<2>>, TypeList<StList<>>>, TypeList<StList<1,5>, StList<2>>>::value , "cartesian product not working"); // Metafunction to count from 0 to n // Count from zero to n-1, and make a sequence of singleton sets containing the numbers template<size_t s> struct Count { typedef Concat_t<typename Count<s-1>::type, TypeList<StList<s-1>>> type; }; template<> struct Count<0> { typedef TypeList<> type; }; template<size_t s> using Count_t = typename Count<s>::type; // Metafunction to abstract a series of for loops, generating the list of all the index tuples the collection of loops would generate template <typename T> struct Volume_Maker; template <> struct Volume_Maker<StList<>> { typedef TypeList<StList<>> type; }; template <size_t s, size_t... sl> struct Volume_Maker<StList<s, sl...>> { typedef Cartesian_Product_t<Count_t<s>, typename Volume_Maker<StList<sl...>>::type> type; }; template <typename T> using Volume_t = typename Volume_Maker<T>::type; // Some more quick unit tests template <typename T> struct Volume_Test { static_assert( Volume_t<T>::length == Compute_Volume<T>::value, "volume computation mismatch"); }; Volume_Test<StList<1,2,3>> test1{}; Volume_Test<StList<1,1,1>> test2{}; Volume_Test<StList<1>> test3{}; Volume_Test<StList<7,6,8>> test4{}; ///////////////// // Grand finale ///////////////// template <typename dim_list, typename idx_list = Volume_t<dim_list>> struct foobar_helper; template <size_t... dim, typename... idx> struct foobar_helper<StList<dim...>, TypeList<idx...>> { typedef StList<dim...> dim_list; typedef std::array<Point<sizeof...(dim)>, sizeof...(idx)> array_type; static constexpr array_type make_array() { return {{ point_maker<idx, dim_list>::make_point()... }}; } }; template <size_t... dim> constexpr std::array<Point<sizeof...(dim)>, Compute_Volume<StList<dim...>>::value> foobar() { return foobar_helper<StList<dim...>>::make_array(); } ///////////////// // Example usage ///////////////// template <size_t ndim> std::ostream & operator << (std::ostream & s, const Point<ndim> & p) { s << "[ "; for (size_t i = 0; i < ndim; ++i) { if (i) { s << ", "; } s << p.data[i]; } s << " ]"; return s; } template<size_t ndim, size_t N> void print_array(std::ostream & s, const std::array<Point<ndim>, N> & a) { for (size_t i = 0; i < N; ++i) { s << a[i] << std::endl; } } int main() { constexpr auto array1 = foobar<2,2,2>(); print_array(std::cout, array1); constexpr auto array2 = foobar<3,3,3,3>(); print_array(std::cout, array2); }