同じシグネチャの関数ポインタを返す関数のシグネチャをtypedefしたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
あごみつ
記事: 17
登録日時: 10年前

同じシグネチャの関数ポインタを返す関数のシグネチャをtypedefしたい

#1

投稿記事 by あごみつ » 10年前

タイトルだと意味不明かもしれないですが、以下のコードでやりたいことはわかっていただけるかと思います

コード:

typedef Handler (*Handler)(int); /* 引数の型は適当です */
侵入型のリスト構造を関数で再現するようなイメージなのですが、お手上げです
よろしくお願いします

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 同じシグネチャの関数ポインタを返す関数のシグネチャをtypedefしたい

#2

投稿記事 by みけCAT » 10年前

少し考えてみましたが、無理かもしれません。

1引数の関数を「引数の型 -> 戻り値の型」と書くことにします。
今作りたい関数(のシグネチャ)は、
作りたい関数 :: int -> 作りたい関数
ですね。
全体の「作りたい関数」を戻り値に代入すると
作りたい関数 :: int -> (int -> 作りたい関数)
もう一度代入すると
作りたい関数 :: int -> (int -> (int -> (int -> 作りたい関数)))
と無限再帰のようになってしまう気がします。

この表現の具体例として、Haskellで例えば「適当な引数を取って自分自身を返す関数」を作ろうとすると、

コード:

GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> let a i = a

<interactive>:2:11:
    Occurs check: cannot construct the infinite type: t1 ~ t -> t1
    Relevant bindings include
      i :: t (bound at <interactive>:2:7)
      a :: t -> t1 (bound at <interactive>:2:5)
    In the expression: a
    In an equation for ‘a’: a i = a
Prelude>
というエラーになってしまいました。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

あごみつ
記事: 17
登録日時: 10年前

Re: 同じシグネチャの関数ポインタを返す関数のシグネチャをtypedefしたい

#3

投稿記事 by あごみつ » 10年前

ご回答ありがとうございます

やっぱり無限再帰になりますよね……
関数の中身は書けるのに宣言が書けないのは嫌な気分です

C++11だとauto使って関数の定義は書けるんですけどね
using Handler = auto (*)(int) -> Handler;
のようにシグネチャは定義出来ないはず(Haskellでもthe infinite typeって言ってますしね)

もう暫く待って他になければ適当なタイミングで解決にしておきます

Bull
記事: 149
登録日時: 11年前

Re: 同じシグネチャの関数ポインタを返す関数のシグネチャをtypedefしたい

#4

投稿記事 by Bull » 10年前

既に回答がありますが、C/C++ではおそらく出来ないと思われます。
代案として、関数の返却値を適当に定義しておいてキャストしてしまう方法が考えられます。

例えばあまりきれいではありませんが

コード:

#include <stdio.h>
#include <stdlib.h>

typedef void (*Handler(int))(int);

Handler* func0(int);

Handler* func2(int n)
{
	printf("IN func2\n");
	if (n <= 0) {
		return NULL;
	} else {
		return (Handler *)func0;
	}
}

Handler* func1(int n)
{
	printf("IN func1\n");
	if (n <= 0) {
		return NULL;
	} else {
		return (Handler *)func2;
	}
}

Handler* func0(int n)
{
	printf("IN func0\n");
	if (n <= 0) {
		return NULL;
	} else {
		return (Handler *)func1;
	}
}

int main(void)
{
	int			count = 10;
	Handler		*handler = (Handler *)func0;


	while (handler != NULL) {
		handler = (Handler *)handler(count--);
	}

	printf("count = %d\n", count);
	return 0;
}
ほかにもポインタを直接返すのではなく、構造体を返す手もあります。

コード:

#include <stdio.h>

int count = 0;

typedef struct tgHANDLE  Handle;
Handle func0(void);

struct tgHANDLE {
    struct tgHANDLE (*func)(void);
};

typedef Handle (*Handler)(void);

Handle func2(void)
{
    Handle   func;

    printf("IN func2\n");
    if (count > 10) {
        func.func = NULL;                   // NULLを返せば終了
    } else {
        ++count;
        func.func = func0;                  // 次の関数
    }
    return func;
}

Handle func1(void)
{
    Handle   func;

    printf("IN func1\n");
    if (count > 10) {
        func.func = NULL;                   // NULLを返せば終了
    } else {
        ++count;
        func.func = func2;                  // 次の関数
    }
    return func;
}

Handle func0(void)
{
    Handle   func;

    printf("IN func0\n");
    if (count > 10) {
        func.func = NULL;                   // NULLを返せば終了
    } else {
        ++count;
        func.func = func1;                  // 次の関数
    }
    return func;
}

int main(void)
{
    Handler   handler;

    handler = func0;                        // 最初の関数のポインタ

    while (handler != NULL) {
        handler = handler().func;
    }

    printf("count = %d\n", count);
    return 0;
}

あごみつ
記事: 17
登録日時: 10年前

Re: 同じシグネチャの関数ポインタを返す関数のシグネチャをtypedefしたい

#5

投稿記事 by あごみつ » 10年前

遅くなりましたが、ご回答ありがとうざいます
わざわざサンプルまで載せていただいて恐縮です

やはり不可能なようなので、ここらで解決にしておきます
ありがとうございました

閉鎖

“C言語何でも質問掲示板” へ戻る