実現したいこと
- サイズの異なるvecterをメンバにもつ構造体をループで同じ処理をしたい
前提
異なるサイズのVectorをメンバに持つ構造体に対して同じ処理をしたい場面があります。
現在は以下のようにひたすら書いているんですが、ループを使って一括で書く方法はないでしょうか。
問題
該当の構造体はフレームワークで提供されるもので変更できません。
該当のソースコード
C++
1enum 2{ 3 TCU, 4 ALE, 5 TMP1, 6 TMP2, 7 TMP3, 8 TMP4, 9 PRS, 10 11TAGCOUNT 12}; 13 14int32_t respSize[TAGCOUNT] {13 ,13 ,6 ,3 ,3 ,3 ,2 }; 15int32_t respData[TAGCOUNT] {5 ,3 ,4 ,35 ,4 ,2 ,1 }; 16 17struct RESP 18{ 19 vector<int32_t> TCU; // 要素数:13 20 vector<int32_t> ALE; // 要素数:13 21 vector<int32_t> TMP1; // 要素数: 6 22 vector<int32_t> TMP2; // 要素数: 3 23 vector<int32_t> TMP3; // 要素数: 3 24 vector<int32_t> TMP4; // 要素数: 3 25 vector<int32_t> PRS; // 要素数: 2 26}; 27 28main() 29{ 30 RESP resp; 31 resp.TCU.assign(respSize[TCU], respDate[TCU]); 32 resp.ALE.assign(respSize[ALE], respDate[ALE]); 33 resp.TMP1.assign(respSize[TMP1], respDate[TMP]); 34 resp.TMP2.assign(respSize[TMP2], respDate[TMP2]); 35 resp.TMP3.assign(respSize[TMP3], respDate[TMP3]); 36};
assing ってなんですか?
誤字です。assignです。修正しました
RESPのデータメンバは質問文では7個ですが、実際も7個ですか?
とりあえず同名の再定義でコンパイル通らないと思うんだけど…
auto *p=&resp.TCU; for(int i=0;i!=5;++i) p[i].assign( size[i], data[i]); みたいな事がやりたい?
(この例は多分UB踏んでると思うけど。踏んでるよね?)

回答する気はないですが、C++の仕様バージョンは書いた方がいいかもですね。

なんか進んでなかったので続きを少し。。。
クラスメンバポインタ
https://learn.microsoft.com/ja-jp/cpp/cpp/pointers-to-members?view=msvc-170
使うとこんな感じになります(const 対応してないけど)。
vector<int32_t>& respMemberByIndex(RESP& resp, int index) {
static vector<int32_t> RESP::* const accessor[RESP_COUNT] = {&RESP::TCU, &RESP::ALE, &RESP::TMP1, &RESP::TMP2, &RESP::TMP3, &RESP::TMP4, &RESP::PRS};
return resp.*accessor[index];
}
void func() {
RESP resp;
for(int i=0;i!=RESP_COUNT;++i)respMemberByIndex(resp, i).assign(respSize[i], respData[i]);
...
}
(C++バージョンがないので)enumは綺麗に扱えません。
C++のバージョンはすいません分からないんです。明日会社に行ったら聞いてみます。
RESPのメンバは可変です。下手すると50とか100とかあります。

可変だとビルド通りませんw
同名の再定義というのは構造体の宣言の話でしょうか?
それともenumと構造体のメンバが同じという意味?
前者ならすいません実際は別の名前で宣言してますので分かりません。
後者は名前は変えてますが、同じ名前でもコンパイル通りました。

TMPが何度も出ていることですよw
>> auto *p=&resp.TCU; for(int i=0;i!=5;++i) p[i].assign( size[i], data[i]); みたいな事がやりたい?
はいその通りです。ですがメンバのサイズが違うのにそれで行けるのかわからなくて。
あとすみません。プログラミング初めてまだ1ヶ月も経ってないのでUBを踏むというのが何かわかりません。
>>TMPがなん℃も出ている
すいません気づきませんでした。実際のメンバ名の前半3文字だけ取ってきていたのでこうなってしまいました。
直します。
>>可変だとビルド通りません
すいません可変というのは自分が書いた後に仕様書が変われば誰かが追加したり、順番が入れ替わったりするかもしれないということです。コンパイルした後にメンバの数が変わることを要求しているわけではありません。
仕様書が変わって書き換えの必要が生じた際に出来るだけ書き換える場所を少なくしておかないと書き換え忘れが生じる可能性があるため、今回の様な質問をさせていただきました。

依存するクラスのメンバ変数が増えて、その変数を使わなければならないのに、こちらの実装が変わるのは当たり前ですよ。それは可変とは言わないし、書き換え忘れるとかの次元の話ではありません。UBというのはUpper Boundary。
>>依存するクラスのメンバ変数が増えて、その変数を使わなければならないのに、こちらの実装が変わるのは当たり前
そうなんですが、実際構造体のメンバに同じ処理をなん度も行っていると、どうにかして関数化、ループによる処理をして、書き換える場所を少なくしておかないと、書き換える場所が1000箇所ぐらいになってしまいます。
>>UBというのはUpper Boundary
すいませんUpper Boundaryで検索してもプログラミング用語としての用法が出てこないんですが、何かのツールでしょうか...

普通に1000箇所しないといけないだけですよ。
どうしても嫌なら相手のコードをパースして実行コードとテストコードを自動生成するしかないですね。

英語くらい調べましょう。なんか以前C++でリフレクションしたいといってゴネてた人みたい。。。
すいません、本当に初心者で分からないことだらけなんです。
Upper Boundaryというのは、ソートされた配列内で、ある値より大きい要素のうち一番左側の位置のこと、で合っていますか?

繰り返します。英語くらい調べましょう。
>> 相手のコードをパースして実行コードとテストコードを自動生成するしかないですね。
実際それを真剣に考えてますが、そのツールをきちんと共有しないと自分以外の人にとっては保守性が悪いことは変わりませんし、アサインされて1ヶ月も経ってない自分がツール作ったんで以降これを使って下さい、とはなかなか言えないです。
>> 英語くらい調べましょう。
Upper Boundaryというのは調べた限りプログラミングの専門用語ではないですし、プログラミングに関連して英文を検索しても前述の様な用法しか出て来ませんでした。具体的にどういう検索をすれば、想定する意味が返ってきますか?

あなたの都合は知りませんよ。ツール作るなら作ればいいし、嫌なら何個でも実装するだけ。
変更するならテストだってしないといけないし、変更忘れなんてありえません。
ツールだってしっかり汎用に作ってしっかりテストされてれば1ヶ月だって使いますよ。
あなたの技量の問題です。

英語も訳せないなら向いてないです。
直訳すれば上側の境界なのは分かりますが、それを踏む、という言葉の意味が分かりません。別の特殊な意味で使われている例を調べた結果前述の様な用法が英文の記事ではヒットするのですが、間違っているのでしょうか。また、こちらの認識が間違っているにも関わらず、ただ自分で調べることを勧めてくることにはどう言った意味があるのでしょうか。

あとは想像力の問題ですね。向いてません。
>> ツールだってしっかり汎用に作ってしっかりテストされてれば1ヶ月だって使う
そうですね、私の技量がそこまで高ければ、そう言ったこともあるかもしれませんが、残念ながら、私はそんなレベルではありません。
>> あとは想像力の問題ですね。向いてません。
そうですね。想像力は乏しい方かもしれません。残念ながら私には相手が何を言いたいのか察する能力が低い様ですので...

まずは嘘をつかずに働くことをオススメします。
残念ながら働いているんです。つい最近までニートみたいな状態でしたが、工場に入ったはずが何故か組み込みの開発部署に異動になり必死です。

じゃあこんなところで聞かずに、現場の人とよく相談してください。
とりあえず組み込みだと処理系が特殊なものであることもあるし(OSのないマイコンは特に)、コンパイラだって不具合がないわけではないので、あまり難しいことをすると煙たがられるケースもありますよ。
例えば私のあげたメソッドポインタとかは使わない方が無難だし、C++の新しい機能使うとか言うとキッチリ検証してない限り嫌がられます。
モノによりますが、PCで動くソフトのように考えない方がいいです。
はい、本当にその通りです。一応VxworksというOS上で動いている様で組み込みと言っても、CPUは IntelのATOM系とかいう話をちらっと聞きました。ですが特殊なことをやるのがNGなのはその通りで、
なので基本的な書き方で今回の様なケースをクリア出来るのではないかと、質問した次第です。
なお当然ですが同僚には質問済みです。c++詳しくないから分からんと言われました。上司はコーディングテクニックの質問に答えてくれるほど暇じゃないと思うので聞きづらいです。
最悪明日の打ち合わせで他の方が如何されてるのかちらっと聞こうとは思ってますが...

VxWorksは大昔使ったことありますよ。制限的な意味だとかなりマシな方だと思いましたが、Linuxとかと比べれば汎用性は低い感じでした。多分どんな現場でもC++で頑張ってる方はいると思うので、改善をしたいのであれば、上司とかに拘らず人脈を増やすのが最善です。現場で師匠的な位置づけの方が見つかるまでは大人しくダルいやり方でやるしかないですね。
大昔、、、これでも新製品の、超精密品の製造機の設計なんですが、、、
ま、まぁ、信頼性が大事な現場では枯れた技術の方が好まれるって言いますし...
ちなみに、別に新人だからいいんですが、全部一個づつ書いてあっても、「うわ、こいつ冗長な書き方してんな。」って馬鹿にされることはないですかね?
まぁコードレビューとかうち全然できてないみたいですが。。。

組み込み制御系は単純な方が好まれるよ。絶対に間違いがないって一目で分かる方が嬉しい。
Undefined Behavior 未定義動作

聞いてみるもんですねw まさかそっちだとは思わなかったw
(未定義動作の)罠を踏むという意味で踏んでると。日本語難しい。
まず,ご自身が危惧している事(:構造体の定義がくっちゃくちゃに変わるかもしれない?)や,現状で「どうなん?」って思ってるようなこと(各メンバに対して同じような処理を延々と書かないとならない?)等々について,その構造体を提供してくる側とよく話し合うべきと思う.
例えば,その構造体の定義が本当に今後変わり得るのだとしても,「あなたが思っているよりもマシな変わり方しかありえない」という想定が可能なのかもしれませんよね.
(e.g. 少なくとも既存のメンバの順序を無意味に入れ替えたり,既存メンバの間に新しいのを差し込んだりとかはしないだろ,みたいな)
示されたコードだけを見た感じからだと,とりあえず
struct REST{ vector<int32_t> Data[TAGCOUNT]; };
のようにしない理由(あえて個々のvectorとして定義する理由)とは何なのか? というあたりからかなぁ.
>あえて個々のvectorとして定義する理由
「該当の構造体はフレームワークで提供されるもので変更できません。」って書いてある。
他人や上司が作ったんでしょ。
だからまず提供側と話せば? って言ってる.
その際にこのあたりの話を切り口にすれば良いのでは?と言ってるだけだ.
提供側が実際に話せる範囲にいないならばどうしようもないだろうが.
誰が作ってるのかさっぱり分かりません。何せ私はまだ同じ部署の10数人の顔を覚えるので必死なので。
ちなみに私が今書いてるのは、過去の製品から流用してきた定義で書いているので、現在要件定義真っ只中の現在開発中の製品の仕様が、確定するのはだいぶ先でしょう。
しかし、とりあえず過去の流用でいいからシュミレーターを作って他のユニットのために動かして欲しい、と言う状態です。実際の製品ではそれぞれのメンバに同じ処理をするなんてそんなにないでしょうから、問題ではないんだと思います。
しかし新製品の仕様が決まるたびにシュミレーターも対応していかなければなりません。結果毎日2、30箇所書き換えが生じます。せめて一つの当たり一箇所の書き換えで済ませたいよぉ、と言うのが私の偽らざる本音です。今日会社に行ったら、メンバの名前は変わるわ、増えるわ減るわ入れ替わるわの地獄でした。全部おんなじような処理なんだから、ボタンひとつで書き換わるようにしたいよぉ。今日は13時間労働だったよぉ。
>>組み込み制御系は単純な方が好まれるよ。絶対に間違いがないって一目で分かる方が嬉しい。
今日上司に全く同じことを言われました。中学生でも上から読んでいけばわかるように書いて欲しいとのことです。

作ってる人とはそのうち話す機会もあるでしょう。ただ違うチームの実装に対して安易に変更要求をするのはお金が絡むので至難の業かもしれません。ただ同時に開発してるなら上を通せば大して手間ではないでしょう。変更前提のモジュールならテストするので、そこで同時に良くなるなら誰の懐も傷まないということです。別に30箇所くらい大した手間ではないですよ。13時間なら普通に寝れるので何の問題もありませんが、開発終盤で法に触れずに無理できるように残業は抑えましょう。
なお、自分のコードだけならスクリプトで実行コードとテストコードを吐くだけで大丈夫です。瞬殺ですね。
>> Undefined Behavior 未定義動作
理解しました。確かに仰っているやり方だとベクターの要素数が違ったり、そもそもintではなくdoubleだったり charだったりするので、何が起こるか分かりません。一応ベースはパソコンと同じ様ですし、現状実験機はなにもつながって無いので、大丈夫だとは思いますが、余り試したくはありません。
>> なお、自分のコードだけならスクリプトで実行コードとテストコードを吐くだけで大丈夫です。瞬殺ですね。
本日はその書き換えスクリプト作成に7時間かかりました。そして完成しませんでした。他に会議4時間あったので実際の仕事としてコード書き換えてたのは、2時間も無いですね。(スクリプト書くより手で書き換えた方が早いんじゃ、、、と10時になったからと会社から追い出されながら思いました。)

未定義動作以前にコンパイルが通らない。Upper Boundaryの解釈は苦肉の策w
> スクリプト書くより手で書き換えた方が早い
書き慣れてない処理や言語だとそうなりがち。スクリプトは時間あるときにやればいいです。
あと(自動化しない)手作業の速度アップは地味に大事。
