c++ - 有没有办法推断函数指针模板参数的值?

标签 c++ templates non-type template-argument-deduction

C++允许非类型模板参数为指针,包括函数指针、类型。我最近问了一个question关于这有什么用,这是对 one of the answers 的跟进.

是否可以从作为相关函数指针的函数参数中推断出函数指针模板参数的?例如:

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

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

如果您想知道这背后的动机,请参阅 this answer 下的评论,特别是可能优化 std::bind() 的实现.

编辑:我意识到我可以简单地删除函数参数并使用模板参数,如 templ<func>() .我添加函数参数的唯一目的是尽量避免必须传递模板参数。

我想我真正想要的是也推断出函数指针的类型,如:

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

然后可以调用

templ(func);

templ<func>();

并从函数指针的单次提及中推导出类型和值。

希望现在更有意义。

最佳答案

函数的模板参数是从函数模板参数的类型中推导出来的。当类型是允许的形式之一时,模板参数只能从类型中推导出来。允许的形式在 [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>
}

请注意,decltypeMAKE_NON_TYPE 宏在这里的使用只是为了方便起见,以避免必须写出 NonType

关于c++ - 有没有办法推断函数指针模板参数的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17736337/

相关文章:

c++ - 从 64 位迁移到 32 位

c++ - 为什么我们在大括号前需要分号?

具有模板成员的 C++ 类,它使用任意模板参数构造模板成员

c++ - 模板非类型参数,C++11,字符串文字的限制

c++ - 允许各种函数类型的非类型模板参数?

python - 简单的 boost::python 程序崩溃

python - 在 C++ 应用程序中嵌入 python 环境

c# - 从内部控件绑定(bind)控件属性

C++ 模板化类给出 `error: non-template X used as template`

c++ - 嵌套类的模板模板参数的可变类型模板参数和非类型模板参数如何相互约束?