Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maintainability suggestions and best practices for template programming

Maintainability of templates is a problem. This is a simple fact, when you're working outside the community dedicated to generic libraries. I don't want my friends and colleagues to have to use Clang to run my code, simply because... well... then it's not really generic and portable, is it? But I do desperately want to be able to write some templated code now and then.

What are some tricks you use to make templated code more usable, more maintainable, and just outright more readable? Things like descriptive template arguments, enable-ifs, and similar little quirks of code style, all the way up to advice regarding things like which compilers support variadic templates or what template (anti-)patterns to avoid.

In short, what idioms should I avoid? Which should I lean on?
I want my code to be elegant but not too elegant.

Some resources I have found:
C++ FAQ
Error Decrypt
What are variadic templates?

like image 225
Jake Kurzer Avatar asked Dec 21 '10 19:12

Jake Kurzer


3 Answers

I use the following approach:

  • Segregate your numerous class helpers in a detail_ namespace; only expose what is necessary.
  • For (almost) each template class, provide a helper function to construct the type: it is especially useful for iterators and functors which can then be constructed inline. Use a good naming scheme for this: iterator_transformer<Iter, F> is constructed by transform_iterator.
  • Use a good naming scheme (nouns for classes, verbs for methods, adjectives for enums). Take a suffix convention (_traits, _concept, ...) and stick to it (1)
  • Have a convention for template metaprogramming: for me type is the "return type" of a metafunction which returns types, value is the static const return type of a function returning a static const integer, other is for metafunctions returning templates. You may want to use boost MPL if you abuse metaprogramming, and follow their conventions (thanks @Noah Roberts)
  • Don't be spewy: do the simplest thing which suits your needs. Use generic programming only if it brings something to your code. Sometimes, plain polymorphism is better.
  • Organize your code in headers: inline implementations go into "implementation headers" files that you #include in your "includable" header
  • Force yourself to use standard algorithms: they make the code more readable
  • Provide toy/test/sample classes, especially if you want people to extend your code.
  • Use typedefs often: you should strive, as usual, not to comment your code.
  • Don't be paranoid with making the compiler fail early: seldom use enable_if, it makes the code less readable. You can use it internally however.
  • You have two main tools: template argument deduction for function templates, and pattern matching with partial specialization of class templates. You should try to use these tools in the most simple way possible. In particular, don't try to overload functions based on whether a type implements a certain concept, or abuse enable_if. Keep it simple.
  • Split the implementation of complex classes into simpler ones. Abuse traits classes in this respect (thanks @Noah Roberts)

(1) I use _concept for base classes for the CRTP pattern (ie. "static polymorphism"). CRTP is good as it allows you to refine a default implementation with minimal code.

like image 124
Alexandre C. Avatar answered Sep 19 '22 21:09

Alexandre C.


I agree with most answers here which state that templates are an (increasingly ?) important component of the language, and that no one can pretend being a C++ developer without an ability to read some reasonable template code.

However, templates can get messy, so I tend to follow a few guidelines :

  • Only show the strict minimum and hide details in a details namespace or, even better, in a separated header file
  • When possible, use default template arguments to ease the syntax : no one likes to write the very same template arguments list over and over
  • Remember that sometimes, templates may also be an implementation detail : them being the implementation of choice for a given problem doesn't prevent you from exposing a single abstract base class to your library users
  • Use typedef as much as possible : when a 'family' of template classes work together and tend to expect the very same template arguments, provide nested typedef (either in the 'main' library object, or in a separate template struct).
  • Comment your code, and most notably express the requirements on each template parameter
like image 32
icecrime Avatar answered Sep 20 '22 21:09

icecrime


I don't really understand. The problems with templates are due to the difficulty of getting the include orders and declaration/definition orders correct, not portability.

Templated code is no less portable than regular code.

like image 37
Puppy Avatar answered Sep 19 '22 21:09

Puppy