template 関数の使い方について – プログラミング – Home

template 関数の使い方について
 
通知
すべてクリア

[解決済] template 関数の使い方について


オーウェル
 オーウェル
(@オーウェル)
ゲスト
結合: 12年前
投稿: 4
Topic starter  

よろしくおねがいします。
v コンテナの各要素の値の大きさで順番を求めその結果を、rv コンテナに取得するプロ
グラムなのですが、行き詰っています。
問題1 関数template の変数out に結果は取得できているのですが、rv コンテナにデー
タを取得することができません、どこがおかしいのでしょうか。
問題2 この関数をポインターや配列でも自由に使えるようにするには、どのようにした
ら良いでしょうか。

#include <iostream> // use std::cout std::endl
#include <vector>

template<class Iterator, class OutputIterator>
void Rank(Iterator first, Iterator last, OutputIterator out)
{
typedef
typename std::iterator_traits<Iterator>::value_type
value_type;

value_type rank = value_type();

for(Iterator p = first; p != last; ++p) {
iterator_traits<Iterator>::value_type lhs = *p;
rank = 1;
for(Iterator q = first; q != last; ++q) {
iterator_traits<Iterator>::value_type rhs = *q;
if(rhs > lhs) {
rank+=1;
}
}
out.push_back( rank );
++rank;
}
}

using namespace std;

int main()
{
vector<int> v, rv;

v.push_back(6);
v.push_back(4);
v.push_back(5);
v.push_back(10);
v.push_back(2);
v.push_back(8);
v.push_back(3);
v.push_back(9);
v.push_back(1);
v.push_back(7);

Rank(v.begin(), v.end(), rv);

vector<int>::iterator it = rv.begin();

while(it != rv.end())
{
cout << *it << endl;
}
}


引用未解決
トピックタグ
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 21年前
投稿: 600
 

こんなもんかしら

#include <iostream>
#include <vector>
#include <iterator>

template<class Iterator, class OutputIterator>
OutputIterator Rank(Iterator first, Iterator last, OutputIterator out) {
typedef typename std::iterator_traits<Iterator>::value_type value_type;

value_type rank = value_type();
for(Iterator p = first; p != last; ++p) {
value_type lhs = *p;
int rank = 1;
for(Iterator q = first; q != last; ++q) {
value_type rhs = *q;
if ( rhs > lhs) {
++rank;
}
}
*out++ = rank;
}
return out;
}

using namespace std;

int main() {
vector<int> v;

v.push_back(6);
v.push_back(4);
v.push_back(5);
v.push_back(10);
v.push_back(2);
v.push_back(8);
v.push_back(3);
v.push_back(9);
v.push_back(1);
v.push_back(7);

vector<int> rv;
Rank(v.begin(), v.end(), back_inserter(rv));
for ( vector<int>::iterator it = rv.begin(); it != rv.end(); ++it ) {
cout << *it << ' ';
}
cout << endl;

int ra[100];
int* la = Rank(v.begin(), v.end(), ra);
for ( int* it = ra; it != la; ++it ) {
cout << *it << ' ';
}
cout << endl;

}


返信引用
オーウェル
 オーウェル
(@オーウェル)
ゲスト
結合: 12年前
投稿: 4
Topic starter  

επιστημη さんありがとうございます。
問題1は、back_inserter() 使うと、値がセットできるんですね。
問題2は、ポインタですね。
ところで、もう一つお聞きしたいのですが、templateはDLLにできるのでしょうか?
templateは鋳型なので、鋳型を作っても実体がなければ無理のような気もするのです
が・・・・
例えば、この関数なんかでもDLL化できるのでしょうか?
本来の質問とは意図が違い恐縮ですがよろしくおねがいします。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 21年前
投稿: 600
 

> ところで、もう一つお聞きしたいのですが、templateはDLLにできるのでしょうか?
> templateは鋳型なので、鋳型を作っても実体がなければ無理のような気もするのです
が・・・・

templateに食わす型が確定していれば、できます。
たとえば std::string は std::basic_string<char> ですからライブラリになります。

型が決まってればもはやtemplateでなくなっちゃってますからね。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 21年前
投稿: 600
 

> back_inserter() 使うと、値がセットできるんですね。

あるいは出来上がりの大きさNがあらかじめわかっているなら:

vector<int> rv(N); // 要素数Nでこしらえておく
Rank(v.begin(), v.end(), rv.begin());


返信引用
オーウェル
 オーウェル
(@オーウェル)
ゲスト
結合: 12年前
投稿: 4
Topic starter  

お世話になります、Template からのDLL 化の方法がよくわかりました、ありがとうござ
います。
ところで、例えば導出する関数プロトタイプをこのように定義をします。
int __stdcall Rank(std::vector<int>::iterator, std::vector<int>::iterator,
vector<int>::iterator)

実装を
Rank(v.begin(), v.end(), back_inserter(rv));
こうした場合
「error C2664: 'Rank' : 3 番目の引数を 'std::back_insert_iterator<_Container>'
から 'std::_Vector_iterator<_Myvec>' に変換できません。(新しい機能 ; ヘルプを参
照)」
型が違うと怒られます、この部分の書き方を教えて頂けないでしょうか。


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

back_inserter は vector::iterator ではないから当然だ。
どうすればいいかは、どうしたいか次第。

俺としては、当該 Rank() を DLL にする、という選択肢がありえない。
DLL 化によって template を使ううまみが消滅しているので。

vector が list に変わったり
int が double に変わったり
back_inserter が front_inserter に変わったり
する可能性はあるの?無いの?
可能性が 1ppm でもあるなら template のまま。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 21年前
投稿: 600
 

おのずとこんな↓カンジになんでねぇかと。

vector<int> rv(v.size());
Rank(v.begin(), v.end(), rv.begin());


返信引用
オーウェル
 オーウェル
(@オーウェル)
ゲスト
結合: 12年前
投稿: 4
Topic starter  

tetrapod さん
>する可能性はあるの?無いの?
無いです、自分自身の考えを整理すると、templateのパターン数あるパターンの中の
一パターンをDLL化したいということになります。
επιστημηさん
>Rank(v.begin(), v.end(), rv.begin());
これやってみたんですが、DLLの側でrv にデータがセットされるのですが、呼び出し側
(exe)のコンテナに値が入って行きません。
と試行錯誤して調べていると、DLLとSTLって相性が非常に悪いようですね、Microsoftさん
なんとかして欲しいところです・・・・orz
stlなんて使わずに、コテコテのC言語のmalloc、freeで実装する方が手っ取り早いのか
な。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 21年前
投稿: 600
 

あー、DLL側でメモリ・アロケートするだろからね。
だったらexe側にcallbackしてはどうでしょね。

int __stdcall Rank(std::vector<int>::iterator, std::vector<int>::iterator,
  void (*func)(int,void*), void* arg) {
...
func(rank,arg);
...
}

とかやっといて:

vector<int> rv;
Rank(v.begin(), v.end(),
[](int r, void* arg) { reinterpret_cast<vector<int>*>(arg)->push_back(r);},
&rv);


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

単に技術的に可能かどうかの検証のため DLL 化した
=速度やわかりやすさなどどうでもいい、って香りがしてきた (爆)

最優先されるのが DLL にすること、であるなら
> コテコテのC言語のmalloc、freeで実装する方が手っ取り早い
に1票。
メモリ操作で EXE/DLL 境界をまたぐとまずい点も解消できそうだし
異コンパイラを使ったり、異コンパイルオプションを使ったりもできるし。


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

技術的興味のためだけにサンプル作ってみた。実用性は0と判断する。
VS2005 ではそれなりに動くが cygwin gcc 4.5.3 ではうまく動かないのを確認済み。
将来の読者の参考にでもなれば幸い。

----rank.hpp---- EXE/DLL 共通の公開ヘッダ
/// 宣言だけ行う
template<typename iit, typename oit>
void __stdcall rank(iit b, iit e, oit o);

#if !defined(DLLDECL)
#define DLLDECL __declspec(dllimport)
#endif

/// 明示的インスタンス化実施
/// 定義なし template を dllimport してよい根拠が無いので
/// たまたま VS2005 では意図通りだが g++ ではだめっぽい
template void DLLDECL __stdcall rank(std::vector<int>::iterator,
std::vector<int>::iterator, std::vector<int>::iterator);
template void DLLDECL __stdcall rank(std::vector<int>::iterator,
std::vector<int>::iterator, std::back_insert_iterator<std::vector<int> >);
template void DLLDECL __stdcall rank(std::vector<int>::iterator,
std::vector<int>::iterator, int*);

----rank.cpp---- rank.dll のソース
#include <vector>
#include <iterator>
#define DLLDECL __declspec(dllexport)
#include rank.hpp

template<typename iit, typename oit>
void __stdcall rank(iit b, iit e, oit o) {
typedef typename std::iterator_traits<iit>::value_type val_type;
for (iit i=b; i!=e; ++i) {
// 元コードの意図がつかみにくいので、勝手に
// 入力イテレータの value_type と同一型を出力すると判断する
// 出力イテレータから value_type を類推すると back_inserter が使えない
val_type rank=val_type(); // 当該型の0を得る
++rank; // 当該型の1を得る
for (iit j=b; j!=e; ++j) {
if (*j<*i) ++rank; // operator< を使うように修正
}
*o=rank; ++o;
}
}
/// 明示インスタンス化指示されたものだけ dllexport される

----rankexe.cpp---- EXE のソース
#include <vector>
#include <iterator>
#include <iostream>
#include rank.hpp

void dump(const std::vector<int>& v) {
std::vector<int>::const_iterator i;
for (i=v.begin(); i!=v.end(); ++i) {
std::cout << *i << ' ';
}
std::cout << std::endl;
}

int main() {
std::vector<int> v;
std::vector<int> w;
v.push_back(1);
v.push_back(-3);
v.push_back(2);
v.push_back(-1);
dump(v);
// inserter が EXE 側にあれば問題ない
rank(v.begin(), v.end(), std::back_inserter(w));
dump(w);
int x[4];
rank(v.begin(), v.end(), x);
for (int i=0; i<4; ++i) std::cout << x[i] << ' ';
std::cout << std::endl;
return 0;
}
-----
cl -LD -EHsc rank.cpp
cl -EHsc rankexe.cpp -link rank.lib

当然ながら DLL で公開していないものは使えないので
const vector<int>& y=v;
rank(y.begin(), y.end(), x);
のように const 1つついただけでリンクエラー発生。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました