Suppose you want to write a function that passes an opaque function descriptor of an unknown type (for example, the name of a structure containing a function with a consistent name) and forwards the arguments to that function.
In the non-invariant case, considering one-parameter functions for simplicity, there are two ways to do this: you can let the forwarding function accept an argument of an arbitrary type and try to call the forwardee function with it, and the compiler will complain when the template is expanded if it turns out to be incompatible; or you can use decltype and various other mechanisms to find out what type of parameter the forwardee function expects, and explicitly requires an argument of that type. I don’t know if there is an acceptable terminology for them, so I’ll call them “passing” and “ahead”.
The pass-through method directly generalizes functions with an arbitrary number of parameters, but the leading edge method does not.
#include <iostream> template<typename T, typename Arg> void pass_through_1(Arg arg) { T::f(arg); } template<typename T> struct arg_of_1; template<typename Ret, typename Arg> struct arg_of_1<Ret (Arg)> { typedef Arg type; }; template<typename T> void up_front_1(typename arg_of_1<decltype(T::f)>::type arg) { T::f(arg); } template<typename T, typename... Args> void pass_through_var(Args... args) { T::f(args...); } template<typename T> struct args_of_var; template<typename...> struct type_list; template<typename Ret, typename... Args> struct args_of_var<Ret (Args...)> { // typedef Args... type; // can't do this typedef type_list<Args...> type; }; // template<typename T> // void up_front_var(typename args_of_var<decltype(T::f)>::type... args) // can't do this // { // T::f(args...); // } struct test { static void f(int x) { std::cout << x*9 << std::endl; } }; int main(int, char**) { pass_through_1<test>(7); up_front_1<test>(8); pass_through_var<test>(9); // up_front_var<test>(10); return 0; }
The problem is that parameter packages cannot be free, only as arguments to the template, and if you wrap them in a covering template, then there is no way to unpack and unpack them in place, only according to the matching template.
Up has some advantages, such as improved self-documentation and better support for type inference (up_front <T> itself can be declared). Is there a way to make it work in the variational case? (Of course, you can use std :: tuple, but this is pretty unsatisfactory.)
source share