9.6. (Member) Function Pointers as Template ArgumentsIntegral constants are not the only kind of non-type template parameters. In fact, almost any kind of value that can be determined at compile time is allowed, including:
We can achieve dramatic efficiency gains by using these kinds of template parameters. When our earlier compose_fg class template is used on two function pointers, it is always at least as large as the pointers themselves: It needs to store the values. When a function pointer is passed as a parameter, however, no storage is needed at all. To illustrate this technique, let's build a new composing function object template: template <class R, class F, F f, class G, G g> struct compose_fg2 { typedef R result_type; template <class T> R operator()(T const& x) const { return f(g(x)); } }; Note, in particular, that compose_fg2 has no data members. We can use it to compute sin2(log2(x)) for each element of a sequence: #include <functional> #include <algorithm> #include <cmath> float input[5] = {0.0, 0.1, 0.2, 0.3, 0.4}; float output[5]; inline float log2(float x) { return std::log(x)/std::log(2); } typedef float (*floatfun)(float); float* ignored = std::transform( input, input+5, output , compose_fg2<float, floatfun,sin_squared, floatfun,log2>() ); Don't be fooled by the fact that there are function pointers involved here: on most compilers, you won't pay for an indirect function call. Because it knows the precise identity of the functions indicated by f and g, the compiler should optimize away the empty compose_fg2 object passed to std::transform and generate direct calls to log2 and sin_squared in the body of the instantiated transform algorithm. For all its efficiency benefits, compose_fg2 comes with some notable limitations.
template <class R, class F, class G>
compose_fg2<R,F,f,G,g> compose(F f, G g)
{
return compose_fg2<R,F,f,G,g>(); // error
}
Unfortunately, any value passed to a function enters the runtime world irretrievably. At that point, there's no way to use it as an argument to a class template without causing a compiler error.[7]
![]() |