アプリ版:「スタンプのみでお礼する」機能のリリースについて

 こんにちは。
今回は、C++ テンプレートで引数に構造体を使えないか悩んでいます。
例えば

#include <stdio.h>

typedef struct _rect{
int x;
int y;
}RECT;

typedef struct _rect{
double x;
double y;
}DATA;

template <calss T>
T Function(T abc)
{
// 構造体の要素にも対応している。
cout << abc//の要素x << endl;
cout << abc//の要素y << endl;

return T;
}

int main()
{
RECT t;
DATA r;

t.x = 80;
t.y = 90;

t = Function(t); // こういった事をしたい
r = Function(r);

return 0;
}

というふうにしたいんです。
テンプレート関数に引数として構造体にしてそれぞれの要素を参照する場合はどうすれば
よろしいのか教えてください。
よろしくお願いします。

A 回答 (8件)

>構造体のメンバ名は統一しないとダメみたいです。



はい、整合性のチェックというのはそれも含んだ意味です。
というより統一した構造体を複数作らないといけないなら

繰り返しになりますが、最初っから


#include <stdio.h>

template < class T >
struct RECTEX {
T x;
T y;
void Function() const {
cout << x << endl;
cout << y << endl;
}
};

int main(void){

RECTEX<int> t = {80,90};
RECTEX<double> r = {1.0,2.0};

t.Function();
r.Function();

return 0;

}


こういったソースにしてしまうのが最善解に思います。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
構造体をテンプレート化してしまった方が扱いやすいということですね。

お礼日時:2012/02/21 00:27

ここまでの文章から勘を働かせると


おそらくCからC++に移行したばかりでご存知なかったのでは
という気がしてきましたので、一応

C++ではstruct にも class にも
変数だけでなく関数も入れておくことができます。

struct A {
int i;
void IncrementI(){ ++i; }
};

この、IncrementIをメンバ関数と呼びます。

A a;
a.i = 7; //a.iは7
a.IncrementI(); //++a.iと同じ結果になり、a.iは処理後8に

「アクセス修飾子」とこの「メンバ関数」を組み合わせることによって
生のC言語と比べ、絶大に読みやすい(或いは保守・拡張が遥かに楽な)
コードを作っていくことができます。

struct のデフォルトのアクセス修飾子はpublic
class のデフォルトのアクセス修飾子はprivate

になっていて、privateというのは、外部から直に触ることが出来ないということになっています。

class A {

int i; //int型のメンバ変数をprivateで一つ持つ。

public: //この下の関数はpublicになります。

//クラス名(); は、「コンストラクタ」という初期化用のメンバ関数です。
A( int i_ ) : i(i_){} //上のメンバint i;を引数のi_で初期化します。

void IncrementI(){ ++i; }

/* メンバ関数の()の後ろにconstを付けると,その関数中では特殊なことをしない限り
メンバ変数は書き変えられる心配がありません。 */
int GetI() const { return i; }

};


A a( 7 ); //コンストラクタに引数7を渡します。a.iは7になります。
a.IncrementI(); //a.iは8になります。

int k = a.GetI(); //kにa.iの現在の数値を代入します。

a.i = 0; /* これはエラー!privateなメンバに外から勝手にアクセスできません。コンパイルは失敗します。*/


こういう風にすることで、不必要なとこで間違って書き変えてしまう恐れを最小限にできるというわけです。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
クラスのアクセス指定子で非公開、公開にできるんですよね。
C++なら構造体ではなくクラスを使うという方法の方がいいんでしょうね。

お礼日時:2012/02/25 15:40

>ステップ数が多いと混乱の元なんでしょうかね。



そうですね。
よっぽど整理されたコードなら多少長くなってもその場その場での混乱が少ないですが

避けられる苦労ならわざわざ自ら選ぶことはありません。


>このxとyもテンプレート化したいといった事はできなんでしょうか?

んん~~?
どういう挙動がお望みなのでしょう?
下のコードでダメっていうのが逆にちょっと分かんない
間違ったコードでもいいので

理想をC++「っぽく」表せますか?


↓とりあえず現時点で、コレの真意、うまみ、骨の髄までしみ渡っていますか? 

template < class T >
struct RECTEX {
T x;
T y;
void Function() const {
std::cout << x << std::endl;
std::cout << y << std::endl;
}
};

この場合の利点は

Functionは「自分自身の構造体のメンバの名前」を使ってるだけなんで
xやyって名前を間違う事は、打ち間違え以外にないだろうってとこにあります。

別の型を作りたかったら、簡単に作れますね

RECTEX<double> a;
RECTEX<int> b;
RECTEX<short> c;
RECTEX<long> d;

メンバの名前を変えたければサクサクっと変えれますね

template < class T >
struct RECTEX {

T 山田が光ると結果的に山田;
T 伸びろ山田;

void Function() const {
std::cout << 山田が光ると結果的に山田 << std::endl;
std::cout << 伸びろ山田 << std::endl;
}

};

これは普通のクラスや構造体とおんなじことです。

struct RECTEX {

int a, b;

void Function() const {
std::cout << a << std::endl; //メンバを使うにはメンバ名が正しくないといけない。
std::cout << b << std::endl;
}

};


逆にいえば、注意することはこれだけで済むという事です。
    • good
    • 0
この回答へのお礼

詳しい解説ありがとうございます。
構造体の中の変数の型も自在に変えら得るようになれたらと思ったんです。
しかしそれでコードが複雑化するなら避けた方がいいと思いました。

お礼日時:2012/02/25 15:37

「メンバへのポインタ」を使えばなんとかなるかと思ったけど, データメンバの場合には static じゃないとテンプレートの引数には渡せなさそう.



とりあえず思い付くのは
・メンバへのポインタについてはテンプレートにするのをあきらめる
・必要なメンバをとりだす関数 (あるいはそのような機能を持つクラス) を作ってテンプレート引数に渡す
くらい.
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
どうやらテンプレートのテンプレートとかは駄目みたいですね。

お礼日時:2012/02/25 15:34

>ところで, stdio.h を #include しても cout は使えないような....



たぶん
省略されてるんじゃないでしょうかねw
と、思って書いたんだけどもw

一応書くと

#include <iostream>
using namespace std;

が、省略されてるはず、ってことでしょうね。

私的にはソースであってもグローバルに
using namespace std;
はさすがにちょっとお勧め致しかねますが。(小さいソースでは別にいいかもしれませんが)

関数内での
using namespace std;
cout, endl
とかあるいは最初から
std::cout, std::endl
とかにする方が

副作用の恐れはだいぶ少ないでしょうね。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
グローバルでの名前空間はしない方がいいとどこかのサイトで
観たことがあります。
ステップ数が多いと混乱の元なんでしょうかね。

お礼日時:2012/02/21 00:32

うぅ~ん, 「構造体のメンバ名は統一しないとダメ」ってのは当たり前だよねぇ. だって,


「の要素x」
とか言い切っちゃってるんだもの. まあこの辺はより具体的に「こんなことがしたい」というのが出てくればそれに合わせるんだけど.

ところで, stdio.h を #include しても cout は使えないような....

この回答への補足

間違いでした。

#include <iostream>

using namespace std;

ですね。

補足日時:2012/02/21 00:28
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

x,yと記述したらそれに合わせなければならないんですね。
このxとyもテンプレート化したいといった事はできなんでしょうか?
質問を重ねるようですみませんが。

お礼日時:2012/02/21 00:30

こんばんは。


この場合だとこれで良いです。

template <class T>
T Function(T abc){
cout << abc.x << endl;
cout << abc.y << endl;
return abc;
}

templateは使用箇所が出てくるまでコードの生成を遅延するという性質があります。
そして「その時に初めて整合性がチェック」されますのでこれで問題ありません。
(ただし型ごとに似たものが内部で作られるので、型が多いと実行ファイルサイズは膨張する可能性があります。)

ただ、abcのコピーコンストラクタが無駄に呼ばれることになりますし
この場合abcをそのまま返す理由もないので


template <class T>
void Function(const T& abc){
cout << abc.x << endl;
cout << abc.y << endl;
}

こちらの方がよろしいかと思います。

ただ、この場合ですと

structのメンバの型が違うだけですので
クラスtemplateを使うのがよろしいかと思います。
ついでに
C++ではtypedef struct {} 何々;
としなくても
struct 何々{};

だけで

何々 hoge;

と使う事ができます。

以上を踏まえて、構造体の内部に持たせてしまう方法


template < class T >
struct RECTEX {
T x;
T y;
void Check() const {
cout << x << endl;
cout << y << endl;
}
};


で十分です。

この場合は

int main(void){

RECTEX<int> t = {80,90};
RECTEX<double> r = {1.0,2.0};

t.Check();
r.Check();

return 0;
}

このような形になります。

この回答への補足

 ありがとうございます。
さっそく試してみました。
構造体のメンバ名は統一しないとダメみたいです。

template <calss T>
T Function(T abc)
{
// 構造体の要素にも対応している。 統一する
cout << abc.x //の要素x << endl;
cout << abc.y //の要素y << endl;

return T;
}

補足日時:2012/02/19 00:45
    • good
    • 0

return T;



return abc;
に変えたらどうでしょうか。

この回答への補足

return T ではなくreturn abcでした。
すいません

補足日時:2012/02/19 00:01
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
確かにその通りですね。

この場合
return T;
です。

お礼日時:2012/02/18 23:47

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!