4

のドキュメントとisSomeFunction次のコードで本当に混乱しています。

static assert(!isFunctionPointer!(typeof(Object.toString)));  // makes sense
static assert(!isDelegate!(typeof(Object.toString)));         // what??
static assert( isSomeFunction!(typeof(Object.toString)));     // what??

誰かが「関数」と「関数ポインタ」の違いを説明してくれませんか?

4

1 に答える 1

6

簡潔な答え:

  • is(T == function)T関数      かどうか
  • isFunctionPointer!TT関数ポインター (デリゲートではない)  かどうか
  • isDelegate!TTデリゲート                かどうか
  • isSomeFunction!TT関数、関数ポインター、またはデリゲートのいずれである        か

長い答え:

関数は、まあ、関数です。

auto func(int val) {...}

これは、その名前を使用して呼び出すことができる名前を持つコードのチャンクです。引数を与えると、何でも実行し、結果を返します。呼び出すことはできますが、渡すことはできません。そのためには関数ポインタが必要です。

関数ポインタは、関数へのポインタです。したがってintintint*が へのポインタであり、 が へのポインタintintないintのと同様に、関数は関数ポインタではありません。関数ポインタが必要な場合は、関数へのポインタが必要です。とは構文が異なりますがint、考え方は同じです。

デリゲートは、状態を持つ関数ポインターです。たとえば、

int foo(int value)
{
    int bar()
    {
        return value + 5;
    }

    auto barDel = &bar;

    return barDel();
}

void main()
{
    auto fooFunc = &foo;
}

foo関数でbarあり、外側のスコープにアクセスできるネストされた関数であり、デリゲートです。これは、状態 (アクセスできるbarDel外側の状態) を持つ関数ポインターであるためです。bar別の関数に渡すbarDel(または返す) と、クロージャーが得られます (渡された関数がデリゲートを受け取る場合を除きます。scopeこの場合、その関数はデリゲートがそのスコープをエスケープしないことを保証します)。呼び出されたときに状態が由来する関数呼び出しが完了した場合でも存在し続けるように、ヒープに置かれます。funcFoo一方、foo外部状態がないため、関数ポインターです。barだったらstaticbarDelまた、デリゲートではなく関数ポインターになります。barこれは、それが含まれる関数にアクセスできなくなるためです (ただし、 にアクセスできなくなるため、本体を変更する必要がありますvalue)。

さて、あなたの例について。Object.toStringのメンバー関数ですObject。というわけで関数です。それに関連付けられた状態はありません。関数は決してしません。その現在の署名は

string toString();

しかし、これは のメンバー関数であるためObject、そのシグネチャは実際には次のようになります。

string toString(Object this);

this引数として渡されtoStringます。に関連付けられた状態ではありませんtoString。だから、&Object.toStringデリゲートではありません。単なる関数ポインタです。AndObject.toStringは関数ポインターではないため、デリゲートで&Object.toString あっstatic assert(isDelegate!(typeof(Object.toString)))たとしても失敗します。デリゲートになるには、関数ポインターである必要がありますが、そうではありません。関数です。

残念ながら、はではなくtypeof(&Object.toString)と見なされるため、実際の呼び出しに使用するには少し手間がかかります。実行できますが、現時点ではその方法を覚えていません (そして、IIRC は少し醜いです)。ただし、状態が関連付けられていないため、デリゲートにはなりません。string function()string function(Object)toStringObject

を渡しObjectてメンバー関数を呼び出すことができる関数が必要な場合は、次のようにすることができます

auto obj = getObjectFromSomewhere();
auto func = function(Object obj){return obj.toString();};
auto result = func(obj);

オブジェクトをメンバー関数に関連付け、オブジェクトを渡すことなくそのオブジェクトでそのメンバー関数を呼び出せるようにする場合は、デリゲートでラップするだけです。

auto obj = getObjectFromSomewhere();
auto del = delegate(){return obj.toString();};
auto result = del();

このコードは物事を要約し、物事をかなりよく示しているはずです:

int foo(int value)
{
    int bar()
    {
        return value + 5;
    }

    static assert( is(typeof(bar) == function));
    static assert(!isFunctionPointer!(typeof(bar)));
    static assert(!isDelegate!(typeof(bar)));
    static assert( isSomeFunction!(typeof(bar)));

    auto barDel = &bar;
    static assert(!is(typeof(barDel) == function));
    static assert(!isFunctionPointer!(typeof(barDel)));
    static assert( isDelegate!(typeof(barDel)));
    static assert( isSomeFunction!(typeof(barDel)));

    static int boz(int i)
    {
        return i + 2;
    }

    static assert( is(typeof(boz) == function));
    static assert(!isFunctionPointer!(typeof(boz)));
    static assert(!isDelegate!(typeof(boz)));
    static assert(isSomeFunction!(typeof(boz)));

    auto bozFunc = &boz;
    static assert(!is(typeof(bozFunc) == function));
    static assert( isFunctionPointer!(typeof(bozFunc)));
    static assert(!isDelegate!(typeof(bozFunc)));
    static assert( isSomeFunction!(typeof(bozFunc)));

    return boz(bar());
}

static assert( is(typeof(foo) == function));
static assert(!isFunctionPointer!(typeof(foo)));
static assert(!isDelegate!(typeof(foo)));
static assert( isSomeFunction!(typeof(foo)));

void main()
{
    auto fooFunc = &foo;
    static assert(!is(typeof(fooFunc) == function));
    static assert( isFunctionPointer!(typeof(fooFunc)));
    static assert(!isDelegate!(typeof(fooFunc)));
    static assert( isSomeFunction!(typeof(fooFunc)));
}

static assert( is(typeof(Object.toString) == function));
static assert(!isFunctionPointer!(typeof(Object.toString)));
static assert(!isDelegate!(typeof(Object.toString)));
static assert( isSomeFunction!(typeof(Object.toString)));

static assert(!is(typeof(&Object.toString) == function));
static assert( isFunctionPointer!(typeof(&Object.toString)));
static assert(!isDelegate!(typeof(&Object.toString)));
static assert( isSomeFunction!(typeof(&Object.toString)));

isSomeFunctionそれらはすべて、関数、状態のない関数ポインター、またはデリゲートtrueのいずれかであるためです。

foobarboz、およびObject.toStringはすべて関数であるため、それらは他のものtrueis(T == function)はありません。

fooFuncbozFunc、およびはstate のない&Object.toString関数ポインターであるため、それらは他のものではありません。trueisFunctionPointer!T

barDelデリゲートなので、他の人のtrueためisDelegate!Tではありません。

うまくいけば、それで問題が解決します。

于 2012-06-17T02:18:23.547 に答える