Как обернуть функцию, используя varargin и varargout?

29

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

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

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

Теги:
variadic-functions
wrapper

3 ответа

36
Лучший ответ

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

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

ans =

   0

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

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

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

Правило:

При выполнении подстрочного присвоения, если

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

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

Например:

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

uninit = 

    [0]
  • 1
    +1 и спасибо за это глубокое понимание! Где ты взял правила выше?
  • 7
    Ну, если честно, полезно, если у вас есть доступ к исходному коду ... Я работаю на The MathWorks. Я не уверен, если это официально задокументировано. Это одна из тех вещей, которая помогает опытному пользователю, но может легко запутать новичков. Тем не менее, я уверен, что это поведение не изменится, потому что это необходимо для обработки этого случая.
Показать ещё 1 комментарий
6
function varargout = wrapper( varargin )

if ~nargout
    someFunction( varargin{:} ); 
else
    [varargout{1:nargout}] = someFunction( varargin{:} ); 
end
  • 0
    О, вы меня опередили на 30 секунд :) У меня был точно такой же ответ.
1

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

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

Это отлично работает с ndgrid.

  • 2
    Помимо опечатки (вы наверняка имеете в виду varargout {1: nargout}), обратите внимание, что этот подход всегда возвращает результат - отсюда и дополнительная охрана Михаила "~ nargout".
  • 0
    @ Эдрик: Я думаю, что использование nargin было нарочно из-за предположения, что nargout=nargin . В этом случае охрана ~nargout не нужна
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню