Metaprogramming vs. generic programming in Fortran

The downside of a preprocessor (like fypp) is it knows relatively little about the semantics of the underlying language getting processed, working mainly through text substitution and macro expansion. E.g. on Wikipedia you may read

The most common example of this is the C preprocessor, … . Because it knows nothing about the underlying language, its use has been criticized and many of its features built directly into other languages.

I think this also reflects some of the opinions in the j3-fortran/fortran_proposals thread on preprocessing. Many use cases for preprocessing could be accommodated within the language.

While stdlib currently uses the approach you’ve just shown (out of pragmatic reasons), it can/does lead to bloated libraries as expressed here. With C++ templates, the compiler will perform something called template specialization, creating and compiling only the versions of the function which are actually needed. There is a nice website called cppinsights.io which shows you the template specialization. This can be very useful when debugging template meta-programs.

Here’s a code example:

template<typename T>
void swap(T& a, T&b) {
  T temp;
  temp = a;
  b = a;
  a = temp;
}

int main(){
  int a{1}, b{2};
  swap(a,b);
  return 0; 
}

And this is the template-specialized version created by the compiler:

template<typename T>
void swap(T& a, T&b) {

  T temp;
  temp = a;
  b = a;
  a = temp;
}

/* First instantiated from: insights.cpp:16 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void swap<int>(int & a, int & b)
{
  int temp;
  temp = a;
  b = a;
  a = temp;
}
#endif


int main()
{
  int a = {1};
  int b = {2};
  swap(a, b);
  return 0;
}

In your Fortran/fypp example you just created and presumably compiled 9 procedures, but perhaps your client code only calls one of them. With C++, you could write a single version with something along the lines of:

template<int N>
double func(...) {
  static_assert(1 <= N && N <= 10,
    "func: integer N out of allowed range (1 <= N <= 10)");
  // ...
}

and which can be called easily in client code

double a;
a = func<5>(...)

No need install a separate preprocessor, minimal bloat.

On the other hand, there are a few negative sides of C++ templates too. Here are some links (some of these are older and might not reflect the current status in C++):

2 Likes