0

I have the following function

template <typename... Args>
void func(Args&&... args){
  // do stuff
}

I now want to create a function pointer, that is callable with a variadic list of arguments, just like the function itself.

template <typename... Args>
using Var_Func = void(*)(Args... args)

At this point, I'm stuck. When creating a variable of type Var_Func, I have to give a list of types for the template:

Var_Func<[List of types]> var_func_p = &func;

This, however, prevents me from calling the pointer with a true variadic list of arguments. I want a pointer, that allows me to call it like a true variadic function, like this:

var_func_p("Test");
var_func_p(0.3, 5);
var_func_p('c', "Another test", 1.3, 3);

I have no idea how to achieve this. Can someone help me?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
user2762996
  • 566
  • 1
  • 5
  • 16
  • what do you need it for? Function pointers point to functions of one specific type. Different instantiations of that template are of different type. [xy problem](https://www.google.com/search?client=firefox-b-d&q=xy+problem) ? – 463035818_is_not_an_ai Sep 03 '20 at 17:10
  • your naming is a bit confusing, `func` for the function and for the pointer. Why do you think you need the pointer? Can't you just call the function directly? – 463035818_is_not_an_ai Sep 03 '20 at 17:16
  • Usually when I find myself in a situation like this I've got a design error. But when I don't, try to abstract away the variability with a [functor](https://stackoverflow.com/questions/356950/what-are-c-functors-and-their-uses). – user4581301 Sep 03 '20 at 17:18

3 Answers3

3

func isn't actually a function. It's a template that the compiler can use to create new functions when it needs to.

When you do func(5) the compiler creates a function called func<int> and then calls it. When you do func(5.0, 'a') the compiler creates a function called func<double, char> and then calls it. These are two completely different, unrelated functions with two different types.

You can create a pointer to func<int> or func<double, char> or func<> or func<anything else> in the usual way. But you cannot ever create a pointer to func, because func is not a function, it's an instruction for the compiler.

user253751
  • 57,427
  • 7
  • 48
  • 90
3

Simply put, this is not possible.

A function template is not a function, it's a template of a function -- and thus it does not have a function pointer until you specify which instantiation you want. At which point, the pointer is fixed to a specific number of arguments of specific types.

It is not possible in the C++ language to type-erase templates into a singular type, such as a pointer that you can pass around and lazily instantiate.

That is, code such as:

some_discrete_variadic_type x = var_func_1;
x(1);
x(1, "2");
x = var_func_2;
x(1);
x(1, "2");

Is not possible, because for type-erasure to work you must normalize the erasure to a fixed number of types (in this case, it would be instantiations).


Depending on what the problem is you are trying to solve, however, there might be workarounds -- though this would require more information.

If your uses are more limited -- such as to pass the functionality into other functions that are only ever known at compile-time, then you can use Functor objects instead and pass them into function templates where the arguments are deduced. For example:

struct var_func
{
    template <typename...Args>
    auto operator()(Args&&...args) -> void
    {
        // do something
    }
};

Where an example of it being called could be:

template <typename T>
auto consume(T var_func_p) -> void
{
    var_func_p("Test");
    var_func_p(0.3, 5);
    var_func_p('c', "Another test", 1.3, 3);
}

int main()
{
    consume(var_func{});
    consume(some_other_var_func{});
}

Note that in this case, you're not passing a function template around anymore. You're passing a static object, var_func, which contains a call-operator (operator()) that is a function template.

Human-Compiler
  • 11,022
  • 1
  • 32
  • 59
  • Thank you for your reply. I will give this a try. What is the meaning of "-> void" after consume and the operator overload? – user2762996 Sep 03 '20 at 19:35
  • It's just a different way of writing the [return type](https://en.cppreference.com/w/cpp/language/function) that was introduced in c++11. `auto consume(T var_func_p) -> void` is the same as writing `void consume(T var_func_p)`. Sorry for being confusing; it's just how I typically write C++ these days. – Human-Compiler Sep 03 '20 at 20:13
2

Like this:

template <typename... Args>
void func(Args&&... args){
  // do stuff
}

template <typename... Args>
using f_ptr = void(*)(Args&&...);

int main() {
    f_ptr<int,int> p = &func<int,int>;
    p(3,1);
}

However, pointers to different instantations of func are incompatible.

This, however, prevents me to call the pointer with a true variadic list of arguments. I want a pointer, that allows me to call it like a true variadic function, like this:

You cannot store a pointer to eg func<double,double> in a f_ptr<int,int>.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185