Is there a way to deduce the value of a function pointer template parameter?

c++, non-type, template-argument-deduction, templates

Solution

Template arguments for a function are deduced from the types of the function's template parameters. Template arguments can only be deduced from a type when that type is one of the allowed forms. The allowed forms are specified in [temp.deduct.type]

Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call it `P`) is compared with an actual type (call it `A`), and an attempt is made to find template argument values (a type for a type parameter, a value for a non-type parameter, or a template for a template parameter) that will make `P`, after substitution of the deduced values (call it the deduced `A`), compatible with `A`.

A template type argument `T`, a template template argument `TT` or a template non-type argument `i` can be deduced if `P` and `A` have one of the following forms:

T
cv-list T
T*
T&
T[integer-constant]
template-name (where template-name refers to a class template)
type(*)(T)
T(*)()
T(*)(T)
T type::*
type T::*
T T::*
T (type::*)()
type (T::*)()
type (type::*)(T)
type (T::*)(T)
T (type::*)(T)
T (T::*)()
T (T::*)(T)
type[i]
template-name<i> (where template-name refers to a class template)
TT<T>
TT<i>
TT<>

where `(T)` represents argument lists where at least one argument type contains a `T`, and `()` represents argument lists where no parameter contains a `T`. Similarly, `<T>` represents template argument lists where at least one argument contains a `T`, `<i>` represents template argument lists where at least one argument contains an `i` and `<>` represents template argument lists where no argument contains a `T` or an `i`.

When considering only non-type template arguments, the relevant forms are those that contain `i`:

type[i]
template-name<i> (where template-name refers to a class template)
TT<i>

Therefore it is not possible to deduce the value directly from the value of a function argument that is the function pointer. However it is possible to deduce the value of a non-type template argument if the function parameter has one of the specified forms.

The following code ahieves this by wrapping the non-type template argument value in a class-template called `NonType`. The parameter of `f` is in the form `template-name<i>`, making it possible for the value of its non-type template argument to be deduced.

template<typename T, T value>
struct NonType {};

template<typename T, T value>
void f(NonType<T, value>)
{
}

void g();

struct A
{
    void f();
    int m;
};

int i;

#define MAKE_NONTYPE(value) NonType<decltype(value), (value)>()

int main()
{
    f(MAKE_NONTYPE(0)); // NonType<int, 0>
    f(MAKE_NONTYPE(&g)); // NonType<void(*)(), &g>
    f(MAKE_NONTYPE(&A::f)); // NonType<void(A::*)(), &A::f>
    f(MAKE_NONTYPE(&A::m)); // NonType<int A::*, &A::m>
    f(MAKE_NONTYPE(&i)); // NonType<int*, &i>
}

Note that `decltype` and the `MAKE_NON_TYPE` macro are used here only as a convenience, to avoid having to write out the full template argument list of `NonType`

Problem

C++ allows non-type template parameters to be of pointer, including function pointer, type. I recently asked a question about what this is useful for, and this is a follow up to one of the answers. Is it posible to deduce the value of a function pointer template parameter, from a function argument that is the function pointer in question? For example: ``` using VoidFunction = void(*)(); template <VoidFunction F> void templ(VoidFunction); ... void func(); // a VoidFunction ... templ<func>(func); // works, but I have to specify the template parameter explicitly templ(func); // <-- I would like to be able to do this ``` Is there a way to get this deduction to happen? It seems technically possible from a compiler implementer's point of view, as long as the function argument can be resolved to a function in the code at compile time. If you're wondering about the motivation behind this, see the comments under this answer, particularly a possible optimization for the implementation of `std::bind()`. EDIT: I realize that I could simply remove the function argument and use the template argument, as in `templ<func>()`. My only purpose of adding in the function argument was to try to avoid having to pass the template argument. I guess what I really want, is to also deduce the type of the function pointer, as in: ``` template <typename Function, Function F> void templ(/* something */); ``` and then be able to call ``` templ(func); ``` or ``` templ<func>(); ``` and have both the type and value be deduced from a single mention of the function pointer. Hope that makes more sense now.

Original source

Related problems