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

Passing function as class template argument

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

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

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是否无效?

[注:用void (*)()代替fun也可以。但这不是我想要的。

像上面那样将函数传递给类模板是否无效?

完全正确,你混淆了类型参数和非类型参数。
fun是一个非类型参数,它是一个函数的地址,就像一个任意数字0x12345678typename T是一个类型参数。您只能传递类型,如int, MyClass, double (*)(std::string), void (MyClass::*)()
你将不得不接受这样一个事实,你需要编译器支持这些东西,或者一些非常丑陋的技巧来推断类型。
如果你喜欢这种把戏,有Boost.Typeof供像你这样的非c++ 0x程序员使用。它还为BOOST_AUTO提供了auto的替代品,但这只是编写BOOST_TYPEOF的一种简短方式:

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

问题?您需要为您拥有的每个用户定义类型帮助它。请看这个Ideone示例。


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

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

有了模板,你又有了函数类型的知识

像上面那样将函数传递到类模板中无效吗?

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

只能对函数进行类型演绎,这意味着即使对类的构造函数也是如此。如果你写一个模板化的构造函数,然后你可以这样写:

Declare obj(&fun); 

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

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


编辑:

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

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

Demo: http://ideone.com/

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

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