gpt4 book ai didi

matlab - 为什么当我重载 subsref(下标引用)时 MATLAB 会抛出 "too many output arguments"错误?

转载 作者:太空宇宙 更新时间:2023-11-03 19:32:40 25 4
gpt4 key购买 nike

作为一个玩具示例,我有一个简单地将向量或矩阵包装在对象中并包含其创建时间的时间戳的类。我正在尝试重载 subsref 以便

  1. () 引用的工作方式与标准向量和矩阵类型完全相同
  2. {} 引用在的工作方式与 () 引用相同(换句话说,与单元格无关)
  3. . 引用允许我访问对象的私有(private) 属性和技术上不属于属性的其他字段。

代码:

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

但是大括号 {} 引用不起作用。我运行这段代码

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}

MException.last 给我这个信息:

identifier: 'MATLAB:maxlhs'
message: 'Too many output arguments.'
cause: {0x1 cell}
stack: [1x1 struct]

这没有帮助,因为异常堆栈中唯一的东西是包含我在上面运行的三行代码的文件。

我在 subsref 中 switch 语句的第一行放置了一个断点,但 MATLAB 从未到达它。

这是怎么回事? (). 引用都按您预期的方式工作,那么为什么 {} 引用不起作用?

最佳答案

当重载花括号 {} 以返回与平时不同数量的输出参数时,还需要重载 numel 以返回预期的数字 (1,在这种情况下)。 更新:R2015b 起,创建了新函数 numArgumentsFromSubscript 以重载,而不是 numel。问题仍然存在,但是应该重载此函数而不是 numel ,正如我在下面的原始答案中所描述的那样。另请参阅页面 "Modify nargout and nargin for Indexing Methods" 。摘录:

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.

下面是对潜在问题的更多解释(需要指定输出参数的数量)。


原始答案(使用 numArgumentsFromSubscript 而不是 R2015b+ 的 numel)

为了在使用花括号进行索引时处理逗号分隔的输出参数列表的可能性,MATLAB 调用 numel 以根据输入索引的大小确定输出参数的数量(根据 this MathWorks answer ) .如果重载 subsref 定义中的输出参数数量与 numel 提供的数量不一致(即小于),则会出现“输出参数过多”错误.正如 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.

由于 x{1:2} 通常提供两个输出 (X{1},X{2}),定义 function x = subsref( B, S) 与此输入不兼容。解决方案是在类中包含一个简单的 numel 方法来重载内置函数,如下所示:

function n = numel(varargin)
n = 1;
end

现在 {} 索引按预期工作,模仿 ():

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

但是,以这种方式重载花括号是 apparently 一种“我们 [MathWorks] 不希望客户编写的特定类型的代码”。 MathWorks 建议:

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.

更新:有趣的是,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.

所以也许现在这个问题已经解决了?


想到的另一种解决方案是将 function x = subsref(B, S) 更改为 function varargout = subsref(B, S) 并添加 varargout=cell(1,numel(B)); varargout{1} = x;.正如 Amro 在评论中指出的那样,预先分配单元格对于避免有关未分配参数的错误是必要的。

关于matlab - 为什么当我重载 subsref(下标引用)时 MATLAB 会抛出 "too many output arguments"错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20863050/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com