narginchk的输出参数太多,为什么MATLAB会抛出“输出参数太多”?我超载subsref(下标引用)时出错?...

As a toy example, I have a class that simply wraps a vector or matrix in an object and includes a timestamp of when it was created. I'm trying to overload subsref so that

() referencing works exactly as it does with the standard vector and matrix types

{} referencing works in exactly the same way as () referencing (nothing to do with cells in other words)

. referencing allows me to access the private properties of the object and other fields that aren't technically properties.

Code:

classdef TimeStampValue

properties (Access = private)

time;

values;

end

methods

%% Constructor

function x = TimeStampValue(values)

x.time = now();

x.values = values;

end

%% Subscripted reference

function x = subsref(B, S)

switch S.type

case '()'

v = builtin('subsref', B.values, S);

x = TimeStampValue(v);

case '{}'

S.type = '()';

v = builtin('subsref', B.values, S);

x = TimeStampValue(v);

case '.'

switch S.subs

case 'time'

x = B.time;

case 'values'

x = B.values;

case 'datestr'

x = datestr(B.time);

end

end

end

function disp(x)

fprintf('\t%d\n', x.time)

disp(x.values)

end

end

end

However brace {} referencing doesn't work. I run this code

clear all

x = TimeStampValue(magic(3));

x{1:2}

and I get this error:

Error using TimeStampValue/subsref

Too many output arguments.

Error in main (line 3)

x{1:2}

MException.last gives me this info:

identifier: 'MATLAB:maxlhs'

message: 'Too many output arguments.'

cause: {0x1 cell}

stack: [1x1 struct]

which isn't helpful because the only thing in the exception stack is the file containing three lines of code that I ran above.

I placed a breakpoint on the first line of the switch statement in subsref but MATLAB never reaches it.

Whats the deal here? Both () and . referencing work as you would expect, so why doesn't {} referencing work?

解决方案

When overloading the curly braces {} to return a different number of output arguments than usual, it is also necessary to overload numel to return the intended number (1, in this case). UPDATE: As of R2015b, the new function "Modify nargout and nargin for Indexing Methods". Excerpt:

When a class overloads numArgumentsFromSubscript, MATLAB calls this method instead of numel to compute the number of arguments expected for subsref nargout and subsasgn nargin.

If classes do not overload numArgumentsFromSubscript, MATLAB calls numel to compute the values of nargout or nargin.

More explanation of the underlying issue (need to specify number of output arguments) follows.

Original answer (use numArgumentsFromSubscript instead of numel for R2015b+)

To handle the possibility of a comma separated list of output arguments when indexing with curly braces, MATLAB calls numel to determine the number of output arguments from the size of the input indexes (according to this MathWorks answer). If the number of output arguments in the definition of overloaded subsref is inconsistent with (i.e. less than) the number provided by numel, you get the "Too many output arguments" error. As stated by MathWorks:

Therefore, to allow curly brace indexing into your object while returning a number of arguments INCONSISTENT with the size of the input, you will need to overload the NUMEL function inside your class directory.

Since x{1:2} normally provides two outputs (X{1},X{2}), the definition function x = subsref(B, S) is incompatible for this input. The solution is to include in the class a simple numel method to overload the builtin function, as follows:

function n = numel(varargin)

n = 1;

end

Now the {} indexing works as intended, mimicking ():

>> clear all % needed to reset the class definition

>> x = TimeStampValue(magic(3));

>> x(1:2)

ans =

7.355996e+05

8 3

>> x{1:2}

ans =

7.355996e+05

8 3

However, overloading curly braces in this manner is apparently a "specific type of code that we [MathWorks] did not expect customers to be writing". MathWorks recommends:

If you are designing your class to output only one argument, it is not recommended that you use curly brace indexing that requires you to overload NUMEL. Instead, it is recommended you use smooth brace () indexing.

UPDATE: Interestingly, the R2015b release notes state:

Before MATLAB release R2015b, MATLAB incorrectly computed the number of arguments expected for outputs from subsref and inputs to subsasgn for some indexing expressions that return or assign to a comma-separated list.

With release R2015b, MATLAB correctly computes the values of nargout and nargin according to the number of arguments required by the indexing expression.

So perhaps this is now fixed?

An alternative solution that comes to mind is to change function x = subsref(B, S) to function varargout = subsref(B, S) and adding varargout=cell(1,numel(B)); varargout{1} = x;. As Amro noted in comments, pre-allocating the cell is necessary to avoid an error about an unassigned argument.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值