7

キャッシュされた評価のための関数があります。引数の 1 つとして、関数ハンドルを取ります。状況によっては、関数ハンドルにアクセスできないことがありますが、その理由はよくわかりません。以下の例は、何が私を困惑させたかを示しています。

>> A.a = @plus; feval(@A.a, 1, 1)

ans =

     2

>> clear A
>> A.a.a = @plus; feval(@A.a.a, 1, 1)
Error using feval
Undefined function 'A.a.a' for input arguments of type 'double'.

そのため、関数ハンドルを構造体のメンバーとして格納している場合、1 レベルの深さであれば問題なく渡すことができますが、2 レベルの深さでは渡すことができません。私の実際の使用例ではD、さまざまなクラスの多くの (117) インスタンスを保持する構造体があるため、実際にはstct.obj.methstctは構造体、objはクラス インスタンス/オブジェクト、methはメソッドです。パス@stct.obj.methは失敗しますが、 を割り当てるA = stct.objと、パスは@A.meth成功します。

どのような条件下で関数ハンドルを引数として渡すことができるので、スタックの下にアクセスできるようになりますか?


編集:上記のユースケースでは、すでに関数ハンドルである@ため、単純に削除できます。@plusただし、次の状況を考慮してください。

>> type cltest.m

classdef cltest < handle
    methods
        function C = mymeth(self, a, b)
            C = a + b;
        end
    end
end

>> A.a = cltest();
>> feval(@A.a.mymeth, 1, 1)
Error using feval
Undefined function 'A.a.mymeth' for input arguments of type 'double'.
>> b = A.a;
>> feval(@b.mymeth, 1, 1)

ans =

     2

この場合、前が必要です...@A.a.mymeth

4

3 に答える 3

1

これを試して:

feval(@(varargin)A.a.mymeth(varargin{:}),1,1);

少しぎこちないですが、うまくいくはずです。

編集:

それが機能する方法は、可変数の引数を取り、それらの引数をメソッドにダンプする匿名関数を作成することA.a.mymeth()です。したがって、実際には関数 Aamymeth にポインターを渡しているのではなく、 を呼び出す A.a.mymeth関数にポインターを渡しています。

を使用せずに同じことを達成する別の方法は次のvararginとおりです。

feval(@(x,y)A.a.mymeth(x,y),1,1);

これにより、2 つの引数を受け取り、それらを に渡す無名関数が作成されA.a.mymethます。

<speculation>単項関数のハンドル演算子が機能する方法に固有のものであるに違いないと思います@。Matlab パーサーは、おそらく が有効な関数である@tokenかどうかを調べて判断します。tokenの場合、が のメンバーであると判断し、適切なハンドルを返すa.mymethほどスマートです。ただし、それがクラスではなく、名前が付けられたメンバーがないため、有効な関数が見つからないことを検出する場合があります。これは、これが機能するという事実によってサポートされているようです。mymethaA.a.mymethAAa.mymeth

A.a.a = @plus; feval(A.a.a,1,1)

これはしません:

A.a.a = @plus; feval(@A.a.a,1,1)

</speculation>

于 2013-10-16T19:54:45.410 に答える
0

@オペレーターが行っていないことを修正する別の関数を導入することで、これを回避できます。

function h=g(f)
x = functions(f);
if ~strcmp(x.type, 'anonymous')
    h = evalin('caller', ['@(varargin)' x.function '(varargin{:})']);
else
    h = f;
end
end

今あなたの例のために:

>> feval(g(@A.a.mymeth), 1, 1)
ans =
     2
>> feval(g(@b.mymeth), 1, 1)
ans =
     2

これにより、コードへの影響が最小限になると思います。もう少しエレガントにできますが、堅牢性や読みやすさは低下します。uplusメソッドはクラスに対して定義されていないため、パスのどこかに次の内容のフォルダーをfunction_handle作成できます。uplus.m@function_handle

function h=uplus(f)
x = functions(f);
if ~strcmp(x.type, 'anonymous')
    h = evalin('caller', ['@(varargin)' x.function '(varargin{:})']);
else
    h = f;
end
end

+@の代わりに使用する必要があります@。あなたの例のために:

>> feval(+@A.a.mymeth, 1, 1)
ans =
     2
>> feval(+@b.mymeth, 1, 1)
ans =
     2
于 2013-10-18T13:21:49.657 に答える