The best solution that I have found is writing a custom (and relatively straightforward) indentation function.
The Code
(defun c++-template-args-cont (langelem)
"Control indentation of template parameters handling the special case of '>'.
Possible Values:
0 : The first non-ws character is '>'. Line it up under 'template'.
nil : Otherwise, return nil and run next lineup function."
(save-excursion
(beginning-of-line)
(if (re-search-forward "^[\t ]*>" (line-end-position) t)
0)))
(add-hook 'c++-mode-hook
(lambda ()
(c-set-offset 'template-args-cont
'(c++-template-args-cont c-lineup-template-args +))))
This handles all of the cases that I have come across even with templates nested several levels deep.
How It Works
For indenting code, if a list of indentation functions is provided, then Emacs will try them in order and if the one currently being executed returns nil
, it will invoke the next one. What I have done is added a new indentation function to the beginning of the list that detects whether the first non-whitespace character on the line is ‘>’, and if it is, set the indentation to position 0 (which will line it up with the opening template). This also covers the case where you have template-template parameters as follows:
template <
template <
typename T,
typename U,
typename... Args
> class... CS
>
because it doesn’t care what’s after the ‘>’. So as a result of how the list of indentation functions works, if ‘>’ is not the first character, the function returns nil
and the usual indentation function gets invoked.