user2762996
user2762996

Reputation: 626

How to create a callable function pointer to a function that has variadic arguments?

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?

Upvotes: 0

Views: 233

Answers (3)

Bitwize
Bitwize

Reputation: 11230

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.

Upvotes: 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.

Upvotes: 3

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 123129

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>.

Upvotes: 2

Related Questions