11

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

foo(foo);

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

void foo(void (*)());

虽然这在 C 中是可以的(并且可以在 C++ 中进行强制转换),但我想知道是否可以在没有如此艰难的“重新解释”强制转换或丢失类型信息的情况下完成。

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

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

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

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

C 风格的答案显示,如何在不强制转换的情况下删除类型信息,或者其他类似的技巧当然很有趣,但不会被接受。

4

8 回答 8

5

显然没有 - 看到这个线程。这里需要的类型总是无限的。

于 2009-10-03T19:35:38.660 回答
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 );
}
于 2009-10-07T08:20:50.450 回答
4

是的

它是“你能编写一个返回指向自身的指针的函数吗?”的变体。,除了在您的情况下,函数类型递归地显示为参数,而不是返回类型。不过,Herb Sutters 的答案是可重用的:将指针包装在前向声明的代理类中。

于 2009-10-05T10:26:43.410 回答
3

一般来说,我同意达里奥的观点——在类型层面上做到这一点似乎是不可能的。

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

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()virtual 或通过在对象中显式存储实现它的函数指针来解决(这基本上是相同的)。

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

于 2009-10-03T19:44:39.870 回答
2

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

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

于 2009-10-03T20:05:50.270 回答
1

我不相信您可以拥有一个可以在 C++ 中将自身作为参数而无需某种技巧的函数,例如将您的函数放入一个类中,并让该函数将该类作为参数。

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

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

请注意,这样的语句在任何支持 lambda 的编译器中都未经测试。你的旅费可能会改变。

于 2009-10-03T20:22:20.353 回答
0

这是对void *.

typedef void T(void *);

void f(T *probably_me)
{
  (*probably_me)(f);
}
于 2009-10-03T19:43:39.767 回答
0

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

于 2009-10-03T19:49:12.683 回答