【初心者歓迎】C/C++室 Ver.33【環境依存OK】 >>951 1. そのとおりでマングリングするしかない。
2. ある。マングリングと呼び出し規約は別問題。
3. DLLを利用する側のヘッダにもinlineで定義すれば平気では?
もっとも、VC++はDLL内の関数をインライン展開できるとMSのサイトに書いてあるのを見た覚えが俺にはある。
4. 絶望的に無理。おとなしくCリンケージにしろ。ただし、COMの影響で仮想関数の呼出はできるはず(マングリング関係ないし)。
>>952 有難うございます。
つまり、現実的には、
・C++リンケージのDLLはコンパイラ依存にならざるを得ない。
・MSVC++でC++のDLLを作りたければ、何も考えずに
classを__declspec(dllexport)するのが一番楽だし
インライン関数のインスタンス化について心配する必要も無い。
・言語、コンパイラ依存を避けたければおとなしくCOMか.NETにしろ。
ってことでしょうか。
一応言っておくと、classをexportするのは、 ヘッダとDLLのバージョン管理とか互換性確保とかが面倒だぞ。
pimplイディオムを使えば 最小限のインターフェースだけ公開できるね
他スレの話ですみませんが、質問です。
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>が再帰して完全に実体化するまで、コンパイルは終わらないと思うし、
もしそうなら、計算はコンパイル時に終わっているのでは?
957 :
951 :2007/01/15(月) 19:50:16
>>954-955 結局、そうした実装の手間と非効率を引き換えにリンク互換性を
追及する行為の行き着く先がCOMだと認識していますが、それで
合ってますか。
>>956 122の場合、コンパイル時に「operator()の数珠繋ぎ」が作られて、
その無駄に長〜い式の答が実行時に計算される。
>>956 えーとそれはenumハックと呼ばれるテクニックで、
const staticが動かなくてもenumのほうは動くというのがよくあるからだと思う。
VC6とかVC6とかVC6とかVC6とかで。
他にもVC6とかVC6とかもあるぞ。
961 :
956 :2007/01/15(月) 21:19:31
>>958 ありがとうございます。申し訳ありませんが、まだよく分かりません。
・enumで書いたコード
・const static int で書いたコード
・opreator() をオーバーロードしたコード
それぞれどのようなコードがマクロ展開後に生成されるのでしょうか?
962 :
956 :2007/01/15(月) 21:22:56
>>959-960 すみません、リロードし忘れていました。
VC6ですか。疑問が解けました。ありがとうございます。
しかし、961はまだ分かりません。
enumはコンパイル時に定数に展開される opreator() は定数を返すだけのコードが生成される それが実行時に数珠繋ぎに呼ばれる
もちろん向こうのスレに書いてあるとおり、 それをコンパイラがコンパイル時に定数展開する最適化を行う可能性はある。
965 :
956 :2007/01/15(月) 22:00:59
>>963-964 ありがとうございます。
もし最適化されなかったら、実行時にsum<1>() 〜 sum<100>()のすべてのイン
スタンスが生成、実行されるということでしょうか?
また、const static int の場合はどうでしょうか?
>>965 >すべてのインスタンスが生成、実行されるということでしょうか?
最適化切ってもそんなことはないと思うが、可能性は否定できない。
>また、const static int の場合はどうでしょうか?
同じことだ。
enumと同じということだな。
968 :
956 :2007/01/15(月) 23:54:07
>>966-967 ありがとうございます。operator() は処理系依存ということですね。
const static int は、enum と違って引数がコンパイル時に決まっている(整
数リテラルである)必要はないので、もしかしたらoperator()同様に実行時解
決されてしまう可能性もあるのかと考えていました。
実際には、コンパイル時に解決されるということですね。
この辺の挙動は、自分の手元の本では全然分かりませんでした。
やはり「プログラミング言語C++第3版」が必要なのかもしれません。
http://www.amazon.co.jp/dp/475611895X
クラス内のstatic const修飾されたものと名前空間内(一見名前空間の外に見える部分も含む)のconst修飾されたものは、 コンパイル時定数となる。その証拠に、配列の要素数に指定できたりテンプレート引数に指定できたりする。 逆にoperator ()はそういうところで使えないことからもコンパイル時定数でないということが伺える。
970 :
956 :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の独自拡張かもしれません。
この挙動を抑制する方法を知りたいのですが、分かりませんでした。
971 :
956 :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 こういう独自拡張はできるだけ抑制したいのですが、やはり方法が見つかりません。
>>970 静的constメンバ変数のクラス内初期化が可能なのは整数型のみ。
よって前者がコンパイルできないのは当たり前。
後者はVC++でオーバーロードが解決できていないだけ。std::cos(1.0)で試せ。
>>971 -可変長引数
+可変長配列
g++ -pedantic
gcc -ansi
975 :
956 :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))];
976 :
956 :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 はコンパイル時定数のようです。
969には「定数式で初期化されているもの」という条件が抜けているような気がする。
// 設定 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秒くらいしか、再生されません どうしたらいいでしょうか
vector(型不定)* を受け取る関数を作ろうとして template <class T> void Func(std::vector<T> *pvec) { 〜略〜 } main() { std::vector<int> vec; Func<int>(&vec); } とやってみたんですが、上手くいきません。 こういうテンプレート型を受け取る関数って どう書けば良いのでしょうか?
>>980 リンカが「未解決の外部シンボル」というエラーを吐きます。
書き忘れてましたが、VC7使用です。
Funcの実装をヘッダ内に書いてないんだろ
>>982 そのとうりです。
テンプレート関数って全部ヘッダで記述しないとダメなんですか(汗
VCはexportをサポートしてないからな
そんなことより、
>>978 をどうにかしてくれ〜〜(泣)
あつかましいにも程がある
>>979 万全を期して、アロケータの分もテンプレート引数にしておけ。
template <class T, class A>
void Func(std::vector<T, A> *pvec)
もっと万全を期してイテレータ受け取ったほうが良くね?
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だと問題があるでしょうか?
>>992 basepairはmypairから見てprotectedだが、引数rpから見たら
見えないのでアクセスできない。
従ってキャストは論理的に正しくない。publicにすべき。
しかもstatic_castではなく、dynamic_castにすべきだと思う。
キャストするならダウンキャストに当たるからdynamic_castだな。 無理矢理感が否めないけど。
ふーん。こういう場合はKoenigの自動照合が働かないのか。 rpはbasepair型なので、basepairの定義からも探されると 思っていたけど違うんだな。
あれ?次スレなくね?
あ
1001 :
1001 :
Over 1000 Thread このスレッドは1000を超えました。 もう書けないので、新しいスレッドを立ててくださいです。。。