問題の解決: 変数は使用前に完全に定義する必要がある
問題
動的に型指定される言語である MATLAB® とは異なり、C と C++ は静的に型指定されます。つまり、コード ジェネレーターは、生成コードでの変数の定義と割り当てのために、MATLAB コード内のすべての変数の型を判別できる必要があります。コード ジェネレーターが MATLAB コード内の 1 つ以上の変数の型を判別できない場合、次の文を含むエラー メッセージがコード ジェネレーターから返されます。
コード生成では、すべての変数を使用前に完全に定義する必要があります。
表示されるエラー メッセージに cell 配列や cell 配列要素に関する言及がある場合は、問題の解決: cell 配列の要素は使用前に完全に定義する必要があるを参照してください。
考えられる解決策
この問題を解決するには、MATLAB コード内のすべての変数にすべての実行パスで値を代入します。これには、構造体フィールドやクラス プロパティなど、他のデータ構造体の中に含まれているすべての変数が含まれます。MATLAB コードと表示される具体的なエラー メッセージに応じて、次のいずれかの解決策を試してください。
すべての実行パスで変数に値を代入する
場合によっては、すべての変数がすべての実行パスで提供されていることをコード ジェネレーターで判別できないことがあります。たとえば、数値入力 x
を受け取って x
の絶対値を返す MATLAB 関数 undefinedVariableTest
を作成します。
function y = undefinedVariableTest(x) %#codegen arguments x (1,1) double end if x == 0 y = 0; elseif x < 0 y = -x; elseif x > 0 y = x; end end
undefinedVariableTest
の呼び出しで x
のすべての値について値が返されます。ただし、else
ステートメントが見つからないため、考えられるすべての実行パスで y
が定義されていることをコード ジェネレーターで判別できず、undefinedVariableTest
のコード生成は失敗します。このコードをコード生成に適したものにするには、else
ステートメントを使用して、考えられるすべての実行パスで y
が定義されていることをコード ジェネレーターに強制的に認識させます。
function y = undefinedVariableTest(x) %#codegen arguments x (1,1) double end if x == 0 y = 0; elseif x < 0 y = -x; else y = x; end end
あるいは、if
ステートメントの外側で y
にダミー値を代入します。
function y = undefinedVariableTest(x) %#codegen arguments x (1,1) double end y = 0; if x == 0 y = 0; elseif x < 0 y = -x; elseif x > 0 y = x; end end
すべての構造体フィールドとクラス プロパティに値を代入する
他のデータ型の中に含まれているすべての変数をすべての実行パスで定義する必要があります。構造体フィールドやクラス プロパティの数または形式は、構造体やクラスが使用された後は変更できません。さらに、特定のコーディング パターンでは、別のデータ型の中に含まれているすべての変数が定義されていることをコード ジェネレーターで認識できません。このような場合は、別のコーディング パターンを使用してコードを書き換えてみてください。
構造体フィールド。コード生成用の MATLAB コードでは、構造体を読み取るか、構造体にインデックスを付けるか、構造体を関数に渡した後は、その構造体にフィールドを追加することはできません。たとえば、構造体 y
を返す MATLAB 関数 undefinedFieldTest
を作成します。x
が 10 より大きい場合、undefinedFieldTest
は値を定義して構造体 s
のフィールド field1
に代入します。それ以外の場合、undefinedFieldTest
は値を定義して構造体 s
の field1
と field2
に代入します。
function y = undefinedFieldTest(x) %#codegen arguments x (1,1) double end if x > 10 s.field1 = 11; else s.field1 = 12; s.field2 = 12; end y = s; end
x
が 10 以下の場合、構造体 s
にフィールド field2
が動的に追加されます。ただし、コード ジェネレーターでは、x
の実行時の値が不明な場合、構造体 s
に含まれるすべてのフィールドの型をコード生成時に判別しなければなりません。フィールド field2
が一部の実行パスでは構造体 s
の一部であるが、他の実行パスではそうでないことがコード ジェネレーターで検出されるため、コード生成は失敗します。このコードをコード生成に適したものにするには、構造体に含まれるフィールドの数や名前が実行時に変わらないようにします。s
のすべてのフィールドを x
の実行時の値に依存せずに定義します。
function y = undefinedFieldTest(x) %#codegen arguments x (1,1) double end s = struct("field1", [], "field2", []); if x > 10 s.field1 = 11; else s.field1 = 12; s.field2 = 12; end y = s; end
クラス プロパティ。クラス プロパティにループで値を代入する特定のコーディング パターンでは、すべてのプロパティが定義されていることをコード ジェネレーターで認識できません。たとえば、正の整数の入力 n
を受け取ってクラス MyClass
のインスタンスを返す MATLAB 関数 undefinedPropTest
を作成します。クラス MyClass
には、prop1
と prop2
という 2 つのプロパティがあります。関数 undefinedPropTest
は、返される myClass
オブジェクトの prop1
と prop2
に for
ループの内部で値を代入します。
function y = undefinedPropTest(n) %#codegen arguments n (1,1) double {mustBePositive, mustBeInteger} end x = MyClass; for i = 1:n x.prop1 = 1 + i; x.prop2 = x.prop1 + 3; end y = x; end
undefinedPropTest
は、許容されるすべての n
の値について MyClass
のインスタンスを返します。ただし、n
のすべての値について prop1
と prop2
に undefinedPropTest
で値が代入されることをコード ジェネレーターで判別できないため、undefinedPropTest
のコード生成は失敗します。このコードをコード生成に適したものにするには、for
ループの前に MyClass
のすべてのプロパティにダミー値を代入します。
function y = undefinedPropTest(n) %#codegen arguments n (1,1) double {mustBePositive, mustBeInteger} end x = MyClass; x.prop1 = 0; x.prop2 = 0; for i = 1:n x.prop1 = 1 + i; x.prop2 = x.prop1 + 3; end y = x; end
すべての永続変数に初期値を代入する
MATLAB コード内のすべての persistent
変数をすべての実行パスで定義する必要があります。たとえば、呼び出された回数を persistent
変数 count
に格納する MATLAB 関数 undefinedPersistentTest
を作成します。count
を初期化またはリセットするには、引数を 0
にして undefinedPersistentTest
を呼び出す必要があります。
function y = undefinedPersistentTest(x) persistent count; if x == 0 count = 0; else count = count + 1; end y = count; end
MATLAB では、永続変数が最初に検出されたときに、その変数が空の行列 ([]
) になるように自動的に設定されます。そのため、count
に値が与えられていても、undefinedPersistentTest
の呼び出しでエラーは発生しません。ただし、コード ジェネレーターでは、初期化されていない永続変数のサイズや型はコード生成時に判別できません。したがって、x
のすべての値について count
が定義されていないことになり、undefinedPersistentTest
のコード生成は失敗します。
このコードをコード生成に適したものにするには、この変数が未定義の場合の値を isempty
関数を使用して count
に代入します。
function y = undefinedPersistentTest(x) arguments x (1,1) double end persistent count; if isempty(count) count = 0; end if x == 0 count = 0; else count = count + 1; end y = count; end
代入なしで変数を定義する
場合によっては、生成コードでの代入による変数の定義には大きなオーバーヘッドが伴います。代入による変数の定義によって、生成コードに変数の余分なコピーができることもあります。変数の代入によるオーバーヘッドなしで変数の型、サイズ、実数/複素数を定義するには、coder.nullcopy
を使用します。
coder.nullcopy
を使用して変数を定義する場合、前述の認識されるコーディング パターンに従わなくてもコードを生成できます。たとえば、関数 nullcopyExample
について考えます。この関数は coder.nullcopy
を使用してクラス MyClass
用にメモリを事前に割り当てるため、このクラスのプロパティにダミー値を代入する必要はありません。
function y = nullcopyExample(n) %#codegen arguments n (1,1) double {mustBePositive, mustBeInteger} end x = coder.nullcopy(MyClass); for i = 1:n x.prop1 = 1 + i; x.prop2 = x.prop1 + 3; end y = x; end
メモ
coder.nullcopy
は注意して使用してください。クラス プロパティ、構造体フィールド、配列要素を含むすべての要素に値が代入されていることを確認する必要があります。初期化されていない変数にアクセスした場合、結果は予測できません。