Conclusion
The Adapter pattern implementation I present here allows for far more flexibility than an equivalent, purely object-oriented implementation. With the proper use of compile-time meta-functions that describe certain traits of adapted types, traits classes to encapsulate those traits, an Adapter base class that defines and enforces an interface with an interface contract and derived classes generated according to the adapted types, we can successfully integrate unit-testable software in an application that has become too cohesive to unit-test, and is not coherent enough to allow for "normal" assumptions about the functioning of the code to be made.
Within the context this solution was found in, the solution is superior to both the object-oriented approach to the Adapter pattern and to a C++ Veneer implementation, which has some, but not all, of the advantages of the solution presented here.
The Task class, described above, is now a simple matter of writing a few of these adapters and the glue to make them stick together.
Notes
[1] The problem, as presented here, is a bit simplified: The actual problem I had to solve had four objects and three types which needed to be passed to the task, each of which could have different types.
[2] See C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond by David Abrahams and Aleksey Gurtovoy for more information.
[3] Both GCC-3.4.4 and MSVC8 perform this optimization.
[4] This is basically the way virtual function calls work, so a way of implementing an abstract interface would be doing the same thing the compiler does: creating a table of "virtual" functions and calling them according to the one that was asked for. Due to C++'s type-safety and a host of conceptual design problems, this is not the way we'll go, though.
[5] For instance, when using a common base class to determine an interface, all derived classes have to implement the base class' interface exactly as presented by the base class, whereas when using a traits class, the exact implementation and signature of the implementation is left to the implementer, and the traits class itself can simply serve as glue-code.
[6] Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.
[7] A Veneer class is much like a classic Adapter in the sense that it also derives from the adaptee and implements a unified interface, and also has the advantage of the Adapter pattern as implemented here. The major difference, though, is that to use Veneers efficiently, you still have to know aforehand what you will be adapting, or fall back to using traits in the same way we d here. Using traits within a Veneer gets a bit more complicated, though, as you're no longer working on a separate class instance. Also, the adapters presented here have a base class that is not a template class and can therefore be stored without knowing the type of the adaptee -- something that can only be accomplished with Veneers when using multiple inheritance, which is something we would like to avoid for now. Veneers are still very interesting in other cases, though, and should definitely not be thrown out of your toolbox because you have this shiny new tool to work with!
[8] As you'll remember, the final application is a bowl of spaghetti of which you can't really expect any coherent behavior. Implementing and enforcing an interface contract top check whether what assumptions you have about its behavior is really what actually happens can save you a lot of trouble in the long run, as it will help pinpoint the location of any bugs within the application, rather than within your adapter.
The Source Code
The source code of every example above is available from from Dr. Dobb's andfrom me.
Only an MSVC8 solution file with its set of project files is provided for compilation, but it should be pretty straightforward to make a little Make file to compile on some other system, and I'll be happy to provide a GNU Makefile for such a purpose.