【初心者歓迎】C/C++室 Ver.33【環境依存OK】

このエントリーをはてなブックマークに追加
952デフォルトの名無しさん:2007/01/15(月) 15:37:07
>>951
1. そのとおりでマングリングするしかない。
2. ある。マングリングと呼び出し規約は別問題。
3. DLLを利用する側のヘッダにもinlineで定義すれば平気では?
もっとも、VC++はDLL内の関数をインライン展開できるとMSのサイトに書いてあるのを見た覚えが俺にはある。
4. 絶望的に無理。おとなしくCリンケージにしろ。ただし、COMの影響で仮想関数の呼出はできるはず(マングリング関係ないし)。
953デフォルトの名無しさん:2007/01/15(月) 15:56:41
>>952
有難うございます。
つまり、現実的には、

・C++リンケージのDLLはコンパイラ依存にならざるを得ない。
・MSVC++でC++のDLLを作りたければ、何も考えずに
 classを__declspec(dllexport)するのが一番楽だし
 インライン関数のインスタンス化について心配する必要も無い。
・言語、コンパイラ依存を避けたければおとなしくCOMか.NETにしろ。

ってことでしょうか。
954デフォルトの名無しさん:2007/01/15(月) 18:09:50
一応言っておくと、classをexportするのは、
ヘッダとDLLのバージョン管理とか互換性確保とかが面倒だぞ。
955デフォルトの名無しさん:2007/01/15(月) 19:09:27
pimplイディオムを使えば
最小限のインターフェースだけ公開できるね
956デフォルトの名無しさん:2007/01/15(月) 19:41:45
他スレの話ですみませんが、質問です。

C++は難しすぎ 難易度:2
http://pc10.2ch.net/test/read.cgi/tech/1071697977/114-122n

116で、どうしてenumを使うのでしょうか?
const static でもいいと思うのですが。
template <int n> struct Sum1 {
  const static int X = Sum1<n-1>::X + n;
};

template<> struct Sum1<1> {
  const static int X = 1;
};

そしてもう一つ、122はどうして実行時に計算されるのでしょうか?
sum<i-1>が再帰して完全に実体化するまで、コンパイルは終わらないと思うし、
もしそうなら、計算はコンパイル時に終わっているのでは?
957951:2007/01/15(月) 19:50:16
>>954-955
結局、そうした実装の手間と非効率を引き換えにリンク互換性を
追及する行為の行き着く先がCOMだと認識していますが、それで
合ってますか。
958デフォルトの名無しさん:2007/01/15(月) 20:42:56
>>956
122の場合、コンパイル時に「operator()の数珠繋ぎ」が作られて、
その無駄に長〜い式の答が実行時に計算される。
959デフォルトの名無しさん:2007/01/15(月) 21:15:33
>>956
えーとそれはenumハックと呼ばれるテクニックで、
const staticが動かなくてもenumのほうは動くというのがよくあるからだと思う。
VC6とかVC6とかVC6とかVC6とかで。
960デフォルトの名無しさん:2007/01/15(月) 21:17:40
他にもVC6とかVC6とかもあるぞ。
961956:2007/01/15(月) 21:19:31
>>958
ありがとうございます。申し訳ありませんが、まだよく分かりません。
・enumで書いたコード
・const static int で書いたコード
・opreator() をオーバーロードしたコード
それぞれどのようなコードがマクロ展開後に生成されるのでしょうか?
962956:2007/01/15(月) 21:22:56
>>959-960
すみません、リロードし忘れていました。
VC6ですか。疑問が解けました。ありがとうございます。
しかし、961はまだ分かりません。
963デフォルトの名無しさん:2007/01/15(月) 21:25:21
enumはコンパイル時に定数に展開される

opreator() は定数を返すだけのコードが生成される
それが実行時に数珠繋ぎに呼ばれる
964デフォルトの名無しさん:2007/01/15(月) 21:43:22
もちろん向こうのスレに書いてあるとおり、
それをコンパイラがコンパイル時に定数展開する最適化を行う可能性はある。
965956:2007/01/15(月) 22:00:59
>>963-964
ありがとうございます。
もし最適化されなかったら、実行時にsum<1>() 〜 sum<100>()のすべてのイン
スタンスが生成、実行されるということでしょうか?

また、const static int の場合はどうでしょうか?
966デフォルトの名無しさん:2007/01/15(月) 23:35:26
>>965
>すべてのインスタンスが生成、実行されるということでしょうか?
最適化切ってもそんなことはないと思うが、可能性は否定できない。

>また、const static int の場合はどうでしょうか?
同じことだ。
967デフォルトの名無しさん:2007/01/15(月) 23:44:41
enumと同じということだな。
968956:2007/01/15(月) 23:54:07
>>966-967
ありがとうございます。operator() は処理系依存ということですね。
const static int は、enum と違って引数がコンパイル時に決まっている(整
数リテラルである)必要はないので、もしかしたらoperator()同様に実行時解
決されてしまう可能性もあるのかと考えていました。
実際には、コンパイル時に解決されるということですね。

この辺の挙動は、自分の手元の本では全然分かりませんでした。
やはり「プログラミング言語C++第3版」が必要なのかもしれません。
http://www.amazon.co.jp/dp/475611895X
969デフォルトの名無しさん:2007/01/15(月) 23:59:02
クラス内のstatic const修飾されたものと名前空間内(一見名前空間の外に見える部分も含む)のconst修飾されたものは、
コンパイル時定数となる。その証拠に、配列の要素数に指定できたりテンプレート引数に指定できたりする。
逆にoperator ()はそういうところで使えないことからもコンパイル時定数でないということが伺える。
970956:2007/01/16(火) 00:34:37
>>969
なるほど、
struct Hoge {
  static const double d = cos(1);
};
これはエラーになるようです。
しかし、

namespace Hoo {
  static const double d = cos(1);
}

これはGCC3.4.3では通ってしまいました。VC++ 2005では通りませんでした。
GCCの独自拡張かもしれません。
この挙動を抑制する方法を知りたいのですが、分かりませんでした。
971956:2007/01/16(火) 00:46:18
static const double d1 = cos(1.0);
int i1[(int)d1];

こういうコードも、VC++だと通りませんが、GCCだとコンパイルを通ってしまいます。
原因は、GCCは配列に可変長引数が使えるからのようです。
http://portable-c.jugem.jp/?eid=23

こういう独自拡張はできるだけ抑制したいのですが、やはり方法が見つかりません。
972デフォルトの名無しさん:2007/01/16(火) 01:01:17
973デフォルトの名無しさん:2007/01/16(火) 01:08:40
>>970
静的constメンバ変数のクラス内初期化が可能なのは整数型のみ。
よって前者がコンパイルできないのは当たり前。

後者はVC++でオーバーロードが解決できていないだけ。std::cos(1.0)で試せ。

>>971
-可変長引数
+可変長配列
g++ -pedantic
974デフォルトの名無しさん:2007/01/16(火) 01:44:18
gcc -ansi
975956:2007/01/16(火) 03:22:47
>>973
ありがとうございます。いろいろ勘違いしていたようです。
-pedantic はうまく行きました。

//こちらはどちらのコンパイラでもコンパイルが通らない。
struct Hoge {
  static const int i = (int) (10*cos(1.0));
};

//こちらはどちらのコンパイラでも通る。
namespace hoge {
  static const int i = (int) (10*cos(1.0));
}

不思議なのは、後半のコードは、>>969さんが
> 名前空間内(一見名前空間の外に見える部分も含む)のconst修飾されたものは、
> コンパイル時定数となる。
とおっしゃっていることと、一致しないように見えることです。

>>974
-ansi では、以下の行がエラーになりませんでした。
int i[(int) (10*cos(1.0))];
976956:2007/01/16(火) 03:28:18
補足ですが、前半のコードのエラーは、以下のようになります。
VC++ → error C2057: 定数式が必要です。
GCC →
error: ‘double cos(double)’ cannot appear in a constant-expression
error: floating-point literal cannot appear in a constant-expression
error: a function call cannot appear in a constant-expression

確かに static constant int はコンパイル時定数のようです。
977デフォルトの名無しさん:2007/01/16(火) 17:01:10
969には「定数式で初期化されているもの」という条件が抜けているような気がする。
978デフォルトの名無しさん:2007/01/17(水) 08:12:02
// 設定
MCI_SET_PARMS set;
set.dwTimeFormat = MCI_FORMAT_TMSF;
mciSendCommand( deviceID, MCI_SET, MCI_SET_TIME_FORMAT | MCI_WAIT, (DWORD)&set );

// トラックの長さ調べる
MCI_STATUS_PARMS status;
status.dwItem = MCI_STATUS_LENGTH;
status.dwTrack = 1;
mciSendCommand( deviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD)&status );

// 再生する
MCI_PLAY_PARMS play;
play.dwFrom = MCI_MAKE_TMSF( 1, 0, 0, 0 );
play.dwTo = MCI_MAKE_TMSF( 1, MCI_MSF_MINUTE(status.dwReturn), MCI_MSF_SECOND(status.dwReturn), MCI_MSF_FRAME(status.dwReturn) );
mciSendCommand( deviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD)&play );


としてるのですが、
曲の長さは2分なのに、なぜか1秒くらいしか、再生されません
どうしたらいいでしょうか
979デフォルトの名無しさん:2007/01/17(水) 10:39:07
vector(型不定)* を受け取る関数を作ろうとして

template <class T>
void Func(std::vector<T> *pvec)
{
  〜略〜
}

main()
{
  std::vector<int> vec;
  Func<int>(&vec);
}

とやってみたんですが、上手くいきません。
こういうテンプレート型を受け取る関数って
どう書けば良いのでしょうか?
980デフォルトの名無しさん:2007/01/17(水) 11:00:48
>>979
>上手くいきません
を説明してくれ。
981デフォルトの名無しさん:2007/01/17(水) 11:12:12
>>980
リンカが「未解決の外部シンボル」というエラーを吐きます。
書き忘れてましたが、VC7使用です。
982デフォルトの名無しさん:2007/01/17(水) 11:15:05
Funcの実装をヘッダ内に書いてないんだろ
983デフォルトの名無しさん:2007/01/17(水) 11:15:52
>>982
そのとうりです。
テンプレート関数って全部ヘッダで記述しないとダメなんですか(汗
984デフォルトの名無しさん:2007/01/17(水) 11:20:48
VCはexportをサポートしてないからな
985デフォルトの名無しさん:2007/01/17(水) 12:58:55
そんなことより、>>978をどうにかしてくれ〜〜(泣)
986デフォルトの名無しさん:2007/01/17(水) 13:04:43
あつかましいにも程がある
987デフォルトの名無しさん:2007/01/17(水) 20:59:14
>>979
万全を期して、アロケータの分もテンプレート引数にしておけ。
template <class T, class A>
void Func(std::vector<T, A> *pvec)
988デフォルトの名無しさん:2007/01/17(水) 21:04:50
もっと万全を期してイテレータ受け取ったほうが良くね?
989質問1(続き):2007/01/17(水) 21:07:52
ソースを次に書きます。

/* 派生クラスで純粋仮想関数をオーバーライドするプログラム */
#include <iostream>
#include <string>
using namespace std;

// basepair抽象クラスの定義
class basepair {
// デフォルトコンストラクタの使用を禁止する
basepair() {}
protected://@ A
//public://@ B
// データメンバ
string key, value;
// 引数をとるコンストラクタ
basepair(const char *pstrkey, const char *pstrval)
: key(pstrkey), value(pstrval) {}
// getvalue()メンバ関数を定義する
const char *getvalue() { return value.c_str(); }
// getkey()メンバ関数を定義する
const char *getkey() { return key.c_str(); }
// keycomp()純粋仮想関数を宣言する
virtual int keycomp(basepair &rp) = 0;
// valcomp()純粋仮想関数を宣言する
virtual int valcomp(basepair &rp) = 0;
// getpairvalue()純粋仮想関数を宣言する
virtual const char *getpairvalue(const char *pstrkey) const = 0;
// getpairkey()純粋仮想関数を宣言する
virtual const char *getpairkey(const char *pstrval) const = 0;
};
//(以下に続く)
990質問1(続き):2007/01/17(水) 21:08:32
// mypair派生クラスの定義
class mypair : public basepair {
public:
// 引数をとるコンストラクタ
mypair(const char *pstrkey, const char *pstrval)
: basepair(pstrkey, pstrval) {}

// keycomp()純粋仮想関数に独自の実装を行う
virtual int keycomp(basepair &rp) {
return strcmp(key.c_str(), (rp).getkey());// A A エラー箇所40行目
// return strcmp(key.c_str(), static_cast<mypair &>(rp).getkey());// A B
}
// valcomp()純粋仮想関数に独自の実装を行う
virtual int valcomp(basepair &rp) {
return strcmp(value.c_str(), (rp).getvalue());// B A エラー箇所45行目
// return strcmp(value.c_str(), static_cast<mypair &>(rp).getvalue());// B B
}
// getpairvalue()純粋仮想関数に独自の実装を行う
virtual const char *getpairvalue(const char *pstrkey) const {
if (key == pstrkey) return value.c_str();
else return NULL;
}
// getpairkey()純粋仮想関数に独自の実装を行う
virtual const char *getpairkey(const char *pstrval) const {
if (value == pstrval) return key.c_str();
else return NULL;
}
};
//(以下に続く)


991質問1(続き):2007/01/17(水) 21:09:16
int main() {
// mypairクラス型の配列を作成する
mypair mp[] = { mypair("358-0015", "さいたまけんいるましにほんぎ"),
mypair("500-8165", "ぎふけんぎふしおいまつちょう"),
mypair("272-0034", "ちばけんいちかわしいちかわ"),
mypair("060-0000", "ほっかいどうさっぽろしちゅうおうく"),
mypair("670-0974", "ひょうごけんひめじしいいだ"),
mypair("770-0874", "とくしまけんとくしましみなみおきのす")
};

if ( mp[5].keycomp(mp[1]) )
{
cout << "mp[5]とmp[1]のKeyは異なる\n";
}
else
{
cout << "mp[5]とmp[1]のKeyは同じ\n";
}

if ( mp[5].keycomp(mp[5]) )
{
cout << "mp[5]とmp[5]のKeyは異なる\n";
}
else
{
cout << "mp[5]とmp[5]のKeyは同じ\n";
}

getchar();

return 0;
}
992質問1(続き):2007/01/17(水) 21:13:35
上記のソースで↓のようなエラーが出ます。

d:\abstract2bad\abstract2bad\abstract2bad.cpp(40) : error C2248: 'basepair::getkey' : protected メンバ (クラス 'basepair' で宣言されている) にアクセスできません。
d:\abstract2bad\abstract2bad\abstract2bad.cpp(20) : 'basepair::getkey' の宣言を確認してください。
d:\abstract2bad\abstract2bad\abstract2bad.cpp(7) : 'basepair' の宣言を確認してください。
d:\abstract2bad\abstract2bad\abstract2bad.cpp(45) : error C2248: 'basepair::getvalue' : protected メンバ (クラス 'basepair' で宣言されている) にアクセスできません。
d:\abstract2bad\abstract2bad\abstract2bad.cpp(18) : 'basepair::getvalue' の宣言を確認してください。
d:\abstract2bad\abstract2bad\abstract2bad.cpp(7) : 'basepair' の宣言を確認してください。

(上のprotected:のをpublic:にすれば勿論問題はないのですがprotectedの
ままで行う場合)
コンパイルを通すにはA、Bで、rpはキャストすればいい(それぞれ、A→B)ようですが、
これって、static_castがベストでしょうか?
dynamicだと問題があるでしょうか?
993デフォルトの名無しさん:2007/01/17(水) 21:45:56
>>992
basepairはmypairから見てprotectedだが、引数rpから見たら
見えないのでアクセスできない。
従ってキャストは論理的に正しくない。publicにすべき。
994デフォルトの名無しさん:2007/01/17(水) 21:48:04
しかもstatic_castではなく、dynamic_castにすべきだと思う。
995デフォルトの名無しさん:2007/01/17(水) 21:53:45
キャストするならダウンキャストに当たるからdynamic_castだな。
無理矢理感が否めないけど。
996デフォルトの名無しさん:2007/01/17(水) 22:03:23
ふーん。こういう場合はKoenigの自動照合が働かないのか。
rpはbasepair型なので、basepairの定義からも探されると
思っていたけど違うんだな。
997デフォルトの名無しさん:2007/01/17(水) 22:05:38
あれ?次スレなくね?
998デフォルトの名無しさん:2007/01/17(水) 22:16:31
立てた

初心者歓迎】C/C++室 Ver.34【環境依存OK】
http://pc10.2ch.net/test/read.cgi/tech/1169039760/
999デフォルトの名無しさん:2007/01/17(水) 22:19:02
>>998
1000デフォルトの名無しさん:2007/01/17(水) 22:22:14
10011001
このスレッドは1000を超えました。
もう書けないので、新しいスレッドを立ててくださいです。。。