有没有办法推断出函数指针模板参数的值? [英] Is there a way to deduce the value of a function pointer template parameter?

查看:160
本文介绍了有没有办法推断出函数指针模板参数的值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++允许非类型模板参数为指针,包括函数指针,类型。我最近询问了一个问题,了解此功能的用途,这是其中一个答案的后续步骤。



是否可以从函数指针的函数参数中推导出函数指针模板参数的?例如:

 使用VoidFunction = void(*)(); 

template< VoidFunction F>
void templ(VoidFunction);

...

void func(); // a VoidFunction

...

templ< func>(func); //工作,但我必须明确指定模板参数
templ(func); //< - 我想能够做到这一点

这个扣除发生?从编译器实现者的角度看,只要函数参数可以在编译时解析为代码中的函数,这在技术上似乎是可能的。



如果你想知道背后的动机,请参阅此答案下的注释,特别是可能的优化实施 std :: bind()



EDIT :我意识到我可以简单地删除函数参数并使用模板参数,如 templ< func>()中所示。我添加在函数参数的唯一目的是试图避免传递模板参数。



我想我真正想要的是,还推导 type ,如下所示:

  template< typename Function,Function F& 
void templ(/ * something * /);

,然后才能呼叫

  templ(func); 

  templ< func>(); 

,并且从单一提及函数指针中推导出类型和值。



希望现在更有意义。

解决方案

函数的模板参数从函数的模板参数的类型推导出。仅当该类型是允许的表单之一时,才能从类型中推导出模板参数。允许的表单在[temp.deduct.type]中指定


模板参数可以在几种不同的上下文中推导出来,在模板参数(调用 P )中指定的类型与实际类型(调用 A ),并尝试查找模板参数值(类型参数的类型,非类型参数的值或模板参数的模板),这将使 P ,替换推导的值(称为推导 A ),与 A 兼容。 / p>

模板类型参数 T ,模板模板参数 TT P A 可以推导出或者模板非类型参数 i code>有以下形式之一:




 T 
cv-list T
T *
T&
T [整数常数]
模板名称(其中模板名称指类模板)
类型(*)(T)
T(*)()
T(*)(T)
T类型:: *
类型T :: *
TT :: *
T类型:: *)()
类型(T :: *)()
类型(类型:: *)(T)
类型$ b T(type :: *)(T)
T(T :: *)()
T(T :: *)(T)
type [i]
template-name<>(其中template-name指类模板)
TT
TT
TT




其中(T)表示参数列表,其中至少一个参数类型包含 / code>,()表示没有参数包含 T 的参数列表。类似地,< T> 表示模板参数列表,其中至少一个参数包含 T < i> 代表至少一个参数包含 i < code>表示模板参数列表,其中没有参数包含 T i


当只考虑非类型模板参数时,相关的形式是包含 i

 type [i] 
template-name<>(其中template-name指类模板)
TT pre>

因此,不可能从作为函数指针的函数参数的值直接推导出值。但是,如果函数参数具有指定形式之一, 可以推断非类型模板参数的值。



以下代码通过将非类型模板参数值包装在名为 NonType 的类模板中来实现。 f 的参数是 template-name< i> 的形式,

 模板< 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>
}

注意 decltype MAKE_NON_TYPE 宏在这里只是为了方便,以避免写出 NonType


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.

解决方案

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

这篇关于有没有办法推断出函数指针模板参数的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆