Как обернуть функцию с помощью varargin и varargout?

мини-пример:

function varargout = wrapper(varargin)
varargout = someFunction(varargin);

Вот как я сделаю это в первую очередь. Но, например, если someFunction = ndgrid, это приводит к ошибке, не определенной для массивов ячеек, поэтому следующая попытка использовала вместо этого someFunction(varargin{:}). Это успешный вызов, но вызов [a,b] = wrapper([1,2], [3,4]) не дает такого же результата, как прямой вызов ndgrid, так что я делаю не так?


person Tobias Kienzler    schedule 04.02.2011    source источник


Ответы (3)


На самом деле ответ Михаила не совсем правильный. В случае, если someFunction - это функция, которая возвращает значение, даже если ничего не запрошено, а именно так функция указывает, что значение должно быть присвоено ans, оболочка Михаила завершится ошибкой. Например, если заменить someFunction на sin и вы напрямую сравните запуск оболочки с запуском sin, вы увидите:

>> wrapper(0)
>> sin(0)

ans =

   0

Правильный способ сделать это

function varargout = wrapper( varargin )
[varargout{1:nargout}] = someFunction( varargin{:} ); 

Причина, по которой это работает, связана с малоизвестным пограничным случаем в правилах индексирования MATLAB, который существовал именно для этого случая, по крайней мере, с R2006a (возможно, дольше). Это что-то вроде бородавки в индексировании MATLAB, но было сочтено необходимым для обработки таких вещей.

Правило такое:

При выполнении присваивания по индексу, если

  • присвоение индексов неинициализированной переменной, И
  • неинициализированная переменная индексируется фигурными скобками, И
  • индекс в фигурных скобках пуст, И
  • левая часть заключена в квадратные скобки, И
  • правая часть разрешается в значение / возвращает результат

Затем неинициализированной переменной присваивается скалярная ячейка, содержащая значение, возвращаемое правой частью.

Например:

>> clear uninit % just to make sure uninit is uninitialized
>> [uninit{[]}] = sin(0)

uninit = 

    [0]
person SCFrench    schedule 06.02.2011
comment
+1 и спасибо за глубокое понимание! Откуда у вас вышеперечисленные правила? - person Mikhail; 06.02.2011
comment
Что ж, если честно, это помогает, если у вас есть доступ к исходному коду ... Я работаю в The MathWorks. Я не уверен, что это где-то официально задокументировано. Это одна из тех вещей, которые помогают продвинутому пользователю, но могут легко запутать новичков. Однако я уверен, что это поведение не изменится, потому что оно необходимо для обработки этого случая. - person SCFrench; 06.02.2011
comment
Спасибо, что поделились, меня это долго беспокоило! - person Erik; 03.08.2016
comment
Хорошие знания, спасибо! Я думаю, что, возможно, использовал это, даже не понимая, почему это работает :-) - person Luis Mendo; 19.02.2021

Если количество выходных аргументов такое же, как количество входных аргументов, вы можете использовать

function varargout = wrapper(varargin)
[varargout{1:nargin}] = someFunction(varargin{:});

Это прекрасно работает с ndgrid.

person mburg    schedule 04.02.2011
comment
Помимо опечатки (вы наверняка имеете в виду varargout {1: nargout}), обратите внимание, что этот подход всегда возвращает результат - отсюда и дополнительная защита ~ nargout Михаила. - person Edric; 04.02.2011
comment
@ Эдрик: Я думаю, что nargin было намеренно из-за предположения nargout=nargin. В этом случае ~nargout охрана не нужна - person Tobias Kienzler; 04.02.2011
comment
@Edric ... также см. ответ SCFrench почему охрана на самом деле не дает желаемого поведения - person Tobias Kienzler; 06.02.2011

person    schedule
comment
Ох, ты опередил меня на 30 секунд :) У меня был точно такой же ответ. - person Edric; 04.02.2011