为什么MATLAB会抛出一个;输出参数太多“;重载subsref(下标引用)时出错?
作为一个玩具示例,我有一个类,它简单地将一个向量或矩阵包装在一个对象中,并包含一个创建它的时间戳。我正在尝试重载subsref为什么MATLAB会抛出一个;输出参数太多“;重载subsref(下标引用)时出错?,matlab,operator-overloading,Matlab,Operator Overloading,作为一个玩具示例,我有一个类,它简单地将一个向量或矩阵包装在一个对象中,并包含一个创建它的时间戳。我正在尝试重载subsrefsubsref,以便 ()引用的工作原理与标准向量和矩阵类型完全相同 {}引用的工作方式与()引用的工作方式完全相同(换句话说,与单元格无关) 引用允许我访问对象的私有属性和其他非技术属性的字段 代码: 但是,大括号{}引用不起作用。我运行这个代码 clear all x = TimeStampValue(magic(3)); x{1:2} 我得到了这个错误: Erro
subsref
,以便
()
引用的工作原理与标准向量和矩阵类型完全相同{}
引用的工作方式与()
引用的工作方式完全相同(换句话说,与单元格无关)
引用允许我访问对象的私有属性和其他非技术属性的字段李>
代码:
但是,大括号{}
引用不起作用。我运行这个代码
clear all
x = TimeStampValue(magic(3));
x{1:2}
我得到了这个错误:
Error using TimeStampValue/subsref
Too many output arguments.
Error in main (line 3)
x{1:2}
meexception.last
向我提供以下信息:
identifier: 'MATLAB:maxlhs'
message: 'Too many output arguments.'
cause: {0x1 cell}
stack: [1x1 struct]
这是没有帮助的,因为异常堆栈中唯一的东西是包含我在上面运行的三行代码的文件
我在subsref
中的switch语句的第一行放置了一个断点,但MATLAB从未到达它
这是怎么回事?
()
和
引用都能像您预期的那样工作,那么为什么{}
引用不能工作呢?当重载花括号{}
以返回与通常不同数量的输出参数时,还需要重载numel
以返回预期的数字(在本例中为1)更新:从R2015b开始,新函数被创建为重载函数,而不是numel
。问题仍然是一样的,但是这个函数应该重载,而不是像我在下面的原始答案中描述的那样numel
。另请参见本页。摘录:
当类重载numArgumentsFromSubscript
时,MATLAB调用此方法而不是numel
,以计算subsref
nargout
和subsasgn
nargin
所需的参数数
如果类没有重载numArgumentsFromSubscript
,MATLAB调用numel
来计算nargout
或nargin
的值
下面将对基本问题进行更多解释(需要指定输出参数的数量)
原始答案(对于R2015b+,使用
numArgumentsFromSubscript
而不是numel
)
为了处理使用大括号编制索引时输出参数列表以逗号分隔的可能性,MATLAB调用numel
,根据输入索引的大小确定输出参数的数量(根据)。如果重载的subsref
定义中的输出参数数量与numel
提供的数量不一致(即小于),则会出现“输出参数过多”错误。如MathWorks所述:
因此,要允许在返回大量与输入大小不一致的参数时将大括号索引到对象中,需要在类目录中重载NUMEL函数
由于x{1:2}
通常提供两个输出(x{1},x{2}
),因此定义函数x=subsref(B,S)
与此输入不兼容。解决方案是在类中包含一个简单的numel
方法来重载内置函数,如下所示:
函数n=numel(varargin)
n=1;
结束
现在,{}
索引按预期工作,模仿()
:
然而,以这种方式重载花括号是“我们[MathWorks]不希望客户编写的特定类型的代码”。MathWorks建议:
如果将类设计为只输出一个参数,则不建议使用要求重载NUMEL的大括号索引。相反,建议您使用平滑大括号()索引
更新:有趣的是:
在MATLAB发布R2015b之前,对于返回或分配给逗号分隔列表的某些索引表达式,MATLAB错误地计算了subsref
输出和subsasgn
输入的预期参数数
在R2015b版本中,MATLAB根据索引表达式所需的参数数量正确计算nargout
和nargin
的值
那么,也许这一问题现在已经解决了
想到的另一种解决方案是将
函数x=subsref(B,S)
更改为函数varargout=subsref(B,S)
,并添加varargout=cell(1,numel(B));varargout{1}=x代码>。正如Amro在评论中所指出的,预先分配单元格对于避免未分配参数的错误是必要的。我刚刚遇到了同样的问题。更糟糕的是,输出参数的数量必须等于numel()
返回的值,这不仅适用于大括号{}
,也适用于点
操作
这意味着,如果覆盖numel()
以返回通常的prod(size(obj))
,则无法访问基础对象的任何属性(如上例中的x.time
),因为subsref()
将返回多个输出
但如果numel()
只返回1,则它与prod(size(obj))
不匹配,这是大多数使用数值或基于restrape()
的代码所期望的。事实上,MATLAB编辑器的气球帮助立即表明“NUMEL(x)通常比PROD(SIZE(x))快”,这表明它们是等效的,但显然不是
一个可能的解决方案是使numel()
返回prod(size(obj))
并显式写入
identifier: 'MATLAB:maxlhs'
message: 'Too many output arguments.'
cause: {0x1 cell}
stack: [1x1 struct]
>> 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
x.get_time()
x.matrix(1,:)
m = x.get_matrix();
m(1,:)
classdef TestClass < handle
methods
function n = numel(~,varargin)
n = 1;
end
function varargout = subsref(input,S)
varargout = builtin('subsref',input,S);
end
function out = twoOutputs(~)
out = {}; out{1} = 2; out{2} = 3;
end
end
end
>> testClass = TestClass();
>> [a,b] = testClass.twoOutouts()
a =
2
b =
3
function [R,varargout] = subsref(P,S)
varargout(1:nargout-1) = cell(1,nargout-1);