mercredi 10 décembre 2008

My take on C++ template metaprogramming

Fortunate accident or deliberate mistake, C++ template metaprogramming should be a tool in any C++ programmer's toolbox ; or should it? Here is what comes to mind when I think about it (in no order at all)

C++ template metaprogramming...

  • useful
  • painful
  • functional
  • long compile times
  • code bloat
  • optimization
  • verbose
  • typename
  • necessary to avoid duplication

With a little work I can put some order in there.

The Good : useful, optimization, necessary to avoid duplication
The Bad : painful, long compile times, code bloat
The Ugly : Well, yeah. It's ugly :-) Syntax Schmintax.

The Good

You need it - you really do. Object-oriented programming failed to kill code duplication. In C++, the only way to write code that has a size pretty much proportionnal to the features you implement is with generic programming. Pretty soon you will see that genericity is not free, you need to consider the different types of parameters you can deal with. If all you want to do is dispatch to different implementations based on type properties you will need to know a little about C++ template metaprogramming. If you are up for a challenge and you try to build your algorithms and data structure in a truly generic way, you'll need to go through whole books... not that it's a bad thing.

The Bad

template< typename src_functor_type, typename kernel_accessor_type >
inline pixel_functor< horizontal_convolution_pixel< pixel_functor< src_functor_type >, kernel_accessor_type > >
convolveh( const pixel_functor< src_functor_type >& src,
const kernel_accessor_type& kernel,
typename kernel_accessor_type::value_type norm )
typedef typename horizontal_convolution_pixel< pixel_functor< src_functor_type >, kernel_accessor_type > fun_type;
return pixel_functor< fun_type >( fun_type( src, kernel, norm ) );

That's what happens when it's used in real life. Since that's some of my own code (from scalex), I hope there are worst examples out there.

Can you see what's happening in that function? It's a simple call to a constructor. That's it. This function exists only so that users don't have to name explicitly all the types that they use. They should not have to because, obviously, those types can be deducted from the context. So there you have it : C++ template metaprogramming means you have functions where the declaration of the return type is longer that the function itself.

There was a time when I wished one day this could be possible :

template< typename T >
auto my_function( const T& parameter )
return some_valid_cpp_expression;

But not anymore. I have lost faith that it will ever happen and if it ever does it will be too little, too late. Because the C++ standard moves too slowly, C++ needs to be programmable.

The Ugly

(let-syntax ((for-range
(syntax-rules ()
((_ type var begin end body ...)
(for (type var begin) (< var end) (++ var) body ...)))))

(function int main ()
(decl float[256] array)
(for-range int i 0 256
(= (array-ref array i) 0.0))
(return 0))))

Lisp! Maybe you did not expect "the visual appeal of oatmeal mixed with nail clippings" but I warned you! Hey, at least it works - the previous "spp" code generates this :

int main ()
float array[256];
for( int i = 0; (i < 256); (++ i) )
(array[i] = 0.0);
return 0;

In this little example code density is not better, but I hope you can get the idea. C++ template metaprogramming is in itself the wrong solution to the code verbosity problem; lisp macros are a better idea. SPP is my take on this. What I'm shooting for with SPP is Bottom-Up programming in C++.

Aucun commentaire: