2013-10-16 7 views
7

캐시 된 평가 기능이 있습니다. 인수 중 하나로서 함수 핸들을 사용합니다. 어떤 상황에서는, 함수 핸들을 접근 할 수없고, 나는 왜 그런지 이해하지 못한다. 아래 예제는 내가 난처한 상황에 빠진있어 보여줍니다 :함수 핸들을 언제 전달할 수 있습니까?

>> 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'. 

을 그래서,이 구조체 멤버로 저장하는 기능 핸들이있는 경우, 그것은 한 단계 깊은 있다면 난 괜찮아 함께 전달할 수 있지만, 두 가지 수준의 깊이입니다하지 않을 경우. 내 실제 사용 사례에서 다양한 클래스의 많은 (117) 인스턴스를 보유하는 구조 D을 가지고 있으므로 실제로는 stct.obj.meth인데 stct은 구조체이고 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 

을, 나는 @

+0

나는 Aamymeth' @'가 유효한 기능 핸들을 생성하지 않는 이유에 대한 좋은 설명이없는, 그러나 당신의 첫 번째 예제에서'추가는 @'아니라는 것을 주목할 필요가있다 필요합니다. 당신은'A.a = @plus; feval (A.a, 1,1);''A.a'가 이미 함수 포인터이기 때문입니다. – nispio

+0

@nispio 예. 그것은 이전에 삭제 된 답변의 요지였습니다. – gerrit

답변

5

소개 클래스가 MATLAB에 대한 큰 문제였다. 사실 너무 크고 여전히 제대로 작동하지 않습니다. 당신의 예제는 구조 접근과 클래스 메소드 접근 충돌을 보여줍니다. 왜냐하면 그들은 도트의 의미를 과부하시켜야했기 때문입니다. ' 원활하게 작동하지 못했습니다. MATLAB 콘솔에서 클래스 메서드를 명시 적으로 이름으로 호출 할 때 어느 정도 작동합니다. 귀하의 예 >> >> A..mymeth (1,1). 그러나 어떤 유형의 간접 참조가 있으면 곧 중단됩니다.

>> @A.a.mymeth으로 함수 핸들을 얻으려고했는데, MATLAB이 이해할 수없는 것은 아마도 혼합 구조/클래스에 혼란스러워 할 수 있습니다. str2func을 사용하여 해결하려고해도 작동하지 않습니다. here과 같이 명시 적 이름 액세스의 경우에만 다시 작동합니다. 예를 들어 깨지기 시작했습니다. >> str2func('b.mymeth'). 수업 내에서도 작동하지 않습니다. 다른 방향을 시도해보고 실패합니다.

또한 MATLAB은 클래스 메서드의 핸들을 제공하지 않습니다. 그것을위한 아무 기능도 없다. 한 번에 모든 함수 핸들을 가져올 방법이 없으며 이름 문자열로 동적으로 처리 할 수도 없습니다.

여기 세 가지 옵션이 있습니다. 먼저 가능한 경우 프로그램을 변경하십시오. 이 함수는 classdef에 있어야합니까?

둘째로, nispio의 해결 방법을 따르십시오. 그들은 둘 다 구성원 메소드에 대한 혼합되지 않은 액세스를 작성하기 위해 클래스 인스턴스에 대한 참조를 보유하는 임시 변수를 작성합니다. 문제는 둘 다 명시 적으로 함수의 이름을 지정해야한다는 것입니다. 관련된 모든 기능에이 코드를 명시 적으로 넣어야합니다. 그 방법을 추상화 할 방법이 없습니다.

셋째, 내부에서 클래스의 메소드 핸들을 제공하여 속이십시오. 구조에서 그들을 내줄 수 있습니다.

classdef cltest < handle 
    methods 
     function C = mymeth(self, a, b) 
      C = a + b; 
     end 
     function hs = funhandles(self) 
      hs = struct('mymeth', @self.mymeth, ... 
         'mymeth2', @self.mymeth2); 
     end 
    end 
end 

그러면 동적으로 이름을 사용하여 핸들에 액세스 할 수 있습니다.

하지만이 방법을 사용하면 외부에서 Access = private 메서드에 액세스 할 수 있습니다.

1

... A.a.mymeth 전에하는 시도 필요 이 :

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

그것은 조금 미봉책이지만, 작동해야합니다.

EDIT :

는 가변 인자를 취하고, 상기 방법으로 이들 인자 A.a.mymeth() 덤프 Anonymous Function를 생성하여 작동하는 방식이다. 따라서 실제로 A.a.mymeth 함수에 대한 포인터를 전달하지 않고 이 호출하는 함수에 대한 포인터를A.a.mymeth으로 전달하고 있습니다.

varargin를 사용하지 않고 같은 일을 달성하는 또 다른 방법 :

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

이 두 개의 인수를 받아들이는 익명 함수를 만들고 A.a.mymeth에 함께 전달합니다.

<speculation> 단항 함수 핸들 연산자 @의 작동 방식에 내재되어 있어야한다고 생각합니다. Matlab 파서는 아마도 @token을보고 token이 유효한 함수인지 여부를 결정합니다. a.mymeth의 경우 mymetha의 구성원인지 확인한 다음 적절한 핸들을 반환하십시오. 그러나 A.a.mymeth을 볼 때 A은 클래스가 아니며 A에는 a.mymeth이라는 멤버가 없으므로 유효한 함수가 없습니다.이것은이 작동한다는 사실에 의해 지원 될 것으로 보인다 :

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

이하지 않습니다 :

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

</speculation>

+0

나는 내 자신의'B = A.a보다 덜 불쾌하다고 생각하지 않는다. feval (@ b.mymeth, 1, 1)'. 문제는 여기서 무엇이 진행되고 있는가? – gerrit

+0

'feval'을 호출하기 전에 b를 덮어 쓰게되면 문제가 생길 수 있기 때문에주의해야 할 해결 방법을주의해야합니다. 내 솔루션이 왜 작동하는지에 대한 설명은 게시물 편집을 참조하십시오. – nispio

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 

나는이 작은 영향을 미칠 것이라고 생각을 귀하의 코드에. 좀 더 우아하지만 덜 강력하고 읽기 쉽도록 만들 수 있습니다.
function h=uplus(f) 
x = functions(f); 
if ~strcmp(x.type, 'anonymous') 
    h = evalin('caller', ['@(varargin)' x.function '(varargin{:})']); 
else 
    h = f; 
end 
end 

지금 당신은 [email protected] 대신 @를 사용해야합니다 :이 내용과 경로에 어딘가에 폴더 @function_handleuplus.m을 만들 수 있도록 uplus 방법은 function_handle 클래스에 정의되어 있지 않습니다.귀하의 예를 들면 다음과 같습니다

>> feval([email protected], 1, 1) 
ans = 
    2 
>> feval([email protected], 1, 1) 
ans = 
    2 
관련 문제