|
Multiple Transparent Codepaths With Partial Specialization
Submitted by |
Here is an example of a method I've found to be quite useful when doing
late optimization.
It shows how to use partial specialization together with template argument
propagation for generating entire codepaths at compile time.
For instance, when you write code for 3DNow, SSE, or AltiVec, you'd only
have to add an enum for each one and write down only the specialized
parts.
The following code fragment shows the implementation of four functions.
One of them has a 3DNow! specialization wich will be transparently used if
3DNow! is available at runtime.
// codepath.cxx
#include <iostream
using std::cerr;
using std::endl;
enum tFeature {
code3DNow,
codeSSE,
codeAltiVec,
codeFPU
};
static int detectFeature() {
// ...
// put here some code to detect the feature to be used
// ...
return code3DNow;
}
// some generic (FPU) functions, packaged in a struct
// for clarity (so we can use "Method2()" instead of
// "Method2<__codepath__()" which is a bit ugly...
template<tFeature __code_path__
struct example {
template<int N, int M
static inline void Method3() {
cerr << "Generic Method3<" << N << ", " << M << "()" << endl;
}
static inline void Method2() {
cerr << "Generic Method2()" << endl;
Method3<12, 23();
}
static inline void Method1() {
cerr << "Generic Method1()" << endl;
Method2();
}
static inline void EntryPoint() {
cerr << "Generic EntryPoint()" << endl;
Method1();
}
};
// 3DNow! version of example::Method1
template<
inline void example<code3DNow::Method1() {
cerr << "3DNow Method1()" << endl;
Method2();
}
// main
int main(void) {
int codePath = detectFeature();
switch (codePath) {
case code3DNow: example<code3DNow::EntryPoint(); break;
case codeSSE: example<codeSSE::EntryPoint(); break;
default: example<codeFPU::EntryPoint(); break;
}
return 0;
}
|
Without 3DNow!, the output would be:
Generic EntryPoint()
Generic Method1()
Generic Method2()
Generic Method3<12, 23>() |
With 3DNow!, however, it would be:
Generic EntryPoint()
3DNow Method1()
Generic Method2()
Generic Method3<12, 23>() |
No test is made in EntryPoint() for choosing the 3DNow version of Method1.
The trick resides in the propagation of a single template argument all
along the call tree. It allow to use inlines, which is impossible with the
Strategy pattern when you don't want to use slow virtual calls.
Julien Cayzac.
|
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
|