我可以声明一个可以将指针作为参数的函数吗?

时间:2009-10-03 19:30:57

标签: c++ c function-pointers

在stackoverflow中读取一个问题,我想知道是否可以声明一个带有指向自身的函数。即做出foo的声明,以下是正确的:

foo(foo);

最简单的想法是转换为另一个函数指针(不能转换为void*,因为它可能更小),所以函数声明如下所示:

void foo(void (*)());

虽然在C中可以使用(并且可以在C ++中使用),但我想知道,如果没有这样的“重新解释”转换或丢失类型信息,是否可以完成。

换句话说,我想要以下声明:

void foo( void (*)( void (*)( void (*) ( ... ))));

但是,当然,无限制的声明是不可能的。天真的typedef也无济于事。

欢迎C ++模板,即使它们使调用代码(foo(foo))看起来不那么简洁,但仍然有限

C风格的答案显示,如何在不进行投射的情况下丢弃类型信息,或者其他类型的技巧当然是有趣的,但不会被接受。

8 个答案:

答案 0 :(得分:5)

显然不是 - 请参阅this thread。这里所需的类型总是无限的。

答案 1 :(得分:5)

另一个肮脏的伎俩。

void Foo( ... )
{
}

int main()
{
 Foo( Foo );
}

以上程序将编译没有任何错误。但它不是递归的。修改后的函数是带有限制器的递归版本。

#define RECURSIVE_DEPTH (5)

typedef void ( *FooType )( int, ... );

void Foo( int Depth, ... )
{
 void ( *This )( int, ... );

 va_list Arguments;

 va_start( Arguments, Depth );

 if( Depth )
 {
  This = va_arg( Arguments, FooType );

  This( Depth - 1, This );
 }

 va_end ( Arguments );  
}

int main()
{
 Foo( RECURSIVE_DEPTH, Foo );
}

答案 2 :(得分:3)

它是"Can you write a function that returns a pointer to itself?"的变体,除了在您的情况下,函数类型递归地显示为argumkent,而不是返回类型。 Herb Sutters的回答是可重用的:将指针包装在前向声明的代理类中。

答案 3 :(得分:2)

一般来说我同意达里奥 - 在类型级别上这似乎是不可能的。

但你可以使用类(“策略模式”):

class A {
  void evil(A a) {       // a pointer to A is ok too
  }
};

您甚至可以添加operator():

  void operator()(A a) { return evil(a); }

一般来说,这些东西在FP语言中做得更好。 Haskell版本很简单:

data Evil = Evil (Evil -> Integer)

这使用与使用类相对应的包装器(Evil)。

来自提问者:这个答案缺少的是将几个不同的函数作为其中一个函数的参数传递的能力。这可以通过使evil()虚拟或通过在对象中显式存储实现它的函数指针(基本相同)来解决。

有了这个澄清,答案就足以被接受了。

答案 4 :(得分:2)

相关问题是返回相同类型的函数指针。它在实现状态机时出现,因此它有自己的entry in the C FAQ

同样的解决方法可以应用于您的问题。

答案 5 :(得分:1)

我不相信你可以拥有一个可以在没有某种技巧的情况下将自己作为C ++中的参数的函数,例如将你的函数放在一个类中,并让函数将该类作为参数。

一旦新的C ++标准命中,可能的另一种方法是使用lambdas,并拥有lambda捕获本身。我认为它会是这样的:

auto recursive_lambda = [&recursive_lambda] { recursive_lambda(); };

请注意,在任何支持lambda的编译器中,这样的语句都是完全未经测试的。您的里程可能会有所不同。

答案 6 :(得分:0)

这是void *的完全有效用途。

typedef void T(void *);

void f(T *probably_me)
{
  (*probably_me)(f);
}

答案 7 :(得分:0)

如果函数可以将自身作为参数,那么它可以通过调用自身来执行匿名递归。但是简单类型的lambda演算中的递归是不可能的(这基本上就是你在这里使用的函数类型)。您需要使用递归函数或递归类型实现定点组合,以便执行匿名递归。