函数类型可以是类模板参数吗?

Can a function type be a class template parameter?

本文关键字:参数 类型 函数      更新时间:2023-10-16

>下面的代码被VC++ 2012拒绝,并显示"错误C2207:'A::bar':类模板的成员无法获取函数类型"。

int Hello(int n)
{
return n;
}
template<class FunctionPtr>
struct A
{
A(FunctionPtr foo)
: bar(foo)
{}
FunctionPtr bar;
};
int main()
{
A<decltype(Hello)> a(Hello);
return 0;
}

为什么?

gcc 对此错误更友好:

error: field 'A<int(int)>::bar' invalidly declared function type

最简单的解决方案是将bar声明为函数指针:

FunctionPtr *bar;

在这种情况下,decltype(Hello)计算结果为int(int)int(*)(int)

变量不能有函数类型。你声明barFunctionPtr这是decltype(Hello)计算结果为int (int)的,而不是函数指针类型。

由于从 C 继承的一些不一致,这令人困惑。当您将A的构造函数定义为采用FunctionPtr时,您可能会认为您会收到相同的错误。但是,声明为具有数组或函数类型的函数参数会自动(不幸的是,不方便)转换为指针类型。因此,即使foo被声明为具有函数类型,它实际上也具有函数指针类型并且工作正常。

但是这个规则只适用于函数参数,而不适用于其他变量,所以bar实际上确实有一个函数类型,这是不合法的。

加上其他答案,您可以利用以下事实:

  • decltype(Hello)计算结果为int (int)(而不是函数指针类型);
  • 函数可以隐式转换为指向自身的指针;这种转换几乎无处不在(例如,按值(?)传递函数而不是函数指针?)。

以下代码:

#include <type_traits>
template<class F>
struct A
{
A(F foo) : bar(foo) {}
typename std::conditional<std::is_function<F>::value,
typename std::add_pointer<F>::type,
F>::type bar;
};

是一个通用解决方案,允许对函数、函数指针、函子和 lambda 使用相同的语法:

#include <type_traits>
#include <iostream>
void Hello() { std::cout << "Functionn"; }
struct Hello2 { void operator()() { std::cout << "Structn"; } };
void Hello3() { std::cout << "Function pointern"; }
template<class F>
struct A
{
A(F foo) : bar(foo) { bar(); }
std::conditional_t<std::is_function<F>::value, std::add_pointer_t<F>, F> bar;
};
int main()
{
A<decltype(Hello)> a(Hello);
Hello2 h2;
A<decltype(h2)> b(h2);
A<decltype(&Hello3)> c(&Hello3);
auto Hello4 = []() { std::cout << "Lambdan"; };
A<decltype(Hello4)> d(Hello4);
}

(在这里,我利用C++14功能稍微更改了解决方案)。

事实上,std::function是一个(并不总是更好的)选择。

今天刚遇到这个问题 - 如果你用decltype((Hello))运行它,应该没问题,而无需更改代码。详见斯科特·迈耶斯