将函数作为类模板参数传递

时间:2011-04-17 04:05:00

标签: c++ templates function-pointers

在不知道函数类型的情况下,我用下面的技术声明它的指针并初始化一个函数指针。

template<typename T>
struct Declare { typedef T Type; }; // for declaring any func ptr

void fun () {}

int main ()
{
  Declare<fun>::Type pf = &fun;  // can't use C++0x 'auto'
}

但是,它会将编译错误称为error: expected a type, got ‘fun’。虽然任何方法的类型在编译时都是已知的。 将函数传递给上述类template是否无效?

[注意:将fun替换为void (*)()可以正常工作。但那不是想要的。]

2 个答案:

答案 0 :(得分:5)

  

如上所述将函数传递给类模板是否无效?

完全可以,你正在混合类型和非类型参数 fun非类型参数,它是函数的地址,如仲裁号0x12345678
typename T类型参数。您只能传递类型,例如intMyClassdouble (*)(std::string)void (MyClass::*)()
你只需要了解事实,你需要编译器支持那些东西或一些非常丑陋的技巧来推断出类型。
如果你正在寻找诡计,那么像你这样的非C ++ 0x编码器有Boost.Typeof。它还为auto BOOST_AUTO提供了一个替代,但这只是撰写BOOST_TYPEOF的简短方法:

int hello(){ return 42; }
BOOST_AUTO(var1,hello()); // type of var1 == int
BOOST_TYPEOF(hello()) var2 = hello(); // same

问题?您需要为每个用户定义的类型提供帮助。请参阅this Ideone example


现在,大多数时候我认为你不需要Boost.Typeof。为什么?因为如果你使用一个函数,你当然需要知道签名,否则你将如何传递正确的参数?或者以正确的方式使用返回类型? 其他时候是模板中的用法。如果你声明一个像auto fptr = &func这样的函数指针,那么你就知道func存在,你知道它的签名和类型。因为当您不知道func存在时,无论如何都需要将它传递给您,最好是在模板中:

template<class FPtr>
void myfunc(FPtr otherfunc){
  // use otherfunc
}

使用模板,您可以再次了解该功能类型。

答案 1 :(得分:3)

  

如上所述将函数传递给类模板是否无效?

是。因为,换句话说,你希望编译器推导出类模板的 type 参数,这在C ++中是不可能的。回想一下fun本身不是类型,它是类型为void (*)()。但是你的类模板需要类型而不是值。这就是为什么它不起作用。

类型推导只能使用函数,即使使用类的构造函数也是如此。因此,如果你编写一个模板化的构造函数,那么你可以这样写:

Declare obj(&fun); 

这里的函数类型是已知的,只要你在构造函数中,一旦你存在它,你就丢失了信息。所以你可能需要的是:定义一个类,比如说,AbstractFunctor(可能是类模板),并从中派生出来定义另一个类template<Fun fun> struct Functor。然后,您可以创建Functor的实例,该实例可以永远记住函数类型,并将实例存储在AbstractFunctor*中作为Declare的成员数据。

但我认为,即使这样,该类型也不能用作Declare::TypeDeclare::AbstractFunctor::Type,因为类型存储在实例中< / em>班级;只有实例知道类型。因此,使用A::Type之类的语法获取类型是不可能的。并且您无法使用语法instance.Type获取类型。您所能做的就是:使用实例调用函数,就像函子一样。


编辑:

如果你被允许使用C ++ 0x的其他功能(不包括auto),那么这个问题有一个简单的解决方案:

Declare<decltype(&fun)>::Type pf = &fun;  
pf(); //call the function

演示:http://ideone.com/

但是,你甚至不需要Declare,因为你可以这样做:

decltype(&fun) pf = &fun; 
pf(); //call the function