Behold, I present you this fucking monstrosity (Directly from the RAJA matrix multiplication tutorial):
using EXEC_POL9 =
RAJA::KernelPolicy<
RAJA::statement::CudaKernel<
RAJA::statement::Tile<1, RAJA::statement::tile_fixed<CUDA_BLOCK_SIZE>, RAJA::cuda_block_y_loop,
RAJA::statement::Tile<0, RAJA::statement::tile_fixed<CUDA_BLOCK_SIZE>, RAJA::cuda_block_x_loop,
RAJA::statement::For<1, RAJA::cuda_thread_y_loop, // row
RAJA::statement::For<0, RAJA::cuda_thread_x_loop, // col
RAJA::statement::Lambda<0>, // dot = 0.0
RAJA::statement::For<2, RAJA::seq_exec,
RAJA::statement::Lambda<1> // dot += ...
>,
RAJA::statement::Lambda<2> // set C = ...
>
>
>
>
>
>;
And that's just for matrix multiplication. I cannot imagine how fucking terrifying it will to write something more complicated than that. If I were to write (and debug) this mindfucking mess of templated code, I would rather escape this trainwreck and go back to writing CUDA/OpenCL code...It's just a Lisp-like language with a slightly different syntax for S-expressions. Ugly, like all Lisps, but nothing 'monstrous'.
C++ templates are far from user-friendly, but they're literally (literally) just Lisp S-expressions with a Lisp syntax and semantics.
I understand complaining about templates like the ranges example also posted in this thread, but I am curious to hear what you think is the alternative for this specific example.
If you want a template challenge, try (without looking it up) writing your own iostream class. iostream is one of those things that's present in even beginner examples but when you look at how it works a whole load of complexity unravels.
My personal rule is to never nest more than two templates. You can have a template inside a template, but anything deeper than that should be refactored or at least split up into typedefs for readability.
However, properly designed templates with enough attention put into exposing functionality beat non-templated approaches right off the bat.
Example: http://eigen.tuxfamily.org/dox/TopicInsideEigenExample.html