関数の呼び出し方について

[戻る]
Milt Jackson 2009/10/11(日) 21:47:42
宜しくお願いします。
このプログラムのコンストラクタからexcel のSUM 計算のようなことを行いたいのですが
error C2440: '=' : 'MovingAve<T,Iterator>' から 'int' に変換できません。
エラーが出ます、何処が不味いのでしょうか?

また、for 文を、transform を用いて書き直したいのですが、
transform( first, last, back_inserter(m_vec), Sum<int>( sum, first, last ) );
としますと、
error C2064: 1 引数を取り込む関数には評価されません。
調べると、関数ポインタとして評価されない式を使って、関数を呼び出そうとしました。
関数のポインタとして評価されない式を使って、関数の呼び出しが行われました。
このエラーは通常、関数でないものを呼び出そうとしたときに発生します。 とのことですが
Sum<int>( sum, first, last ) 恐らくこの部分の定義、または、呼び出し方法が間違っ
ていると想像しますがわかりません
合わせてご教示願えないでしょうか。
(コンパイラVS2005)
#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>
using namespace std;

template <class T, class Iterator>
class MovingAve
{
    Iterator first_;
    Iterator last_;
public:
    MovingAve(Iterator first = MovingAve(), Iterator last = MovingAve()) :
first_(first), last_(last) {}
    T operator()(Iterator first, Iterator last);
    T Sum(Iterator& first, Iterator& last);
};

template <class T, class Iterator>
T MovingAve<T, Iterator>::operator()(Iterator first, Iterator last)
{
    T sum = 0;
    while ( first_ != last_ ) {
        sum+=*first_;
        ++first_;
    }
    return sum;
}

template <class T, class Iterator>
T Sum(Iterator& first, Iterator& last)
{
    T sum = 0;
    while ( first != last ) {
        sum+=*first;
        ++first;
    }
    return sum;
}

int main()
{
    int sum;
    vector<int> vec, m_vec;
    vector<int>::iterator first, last;
    for( int i = 0; i<10 ;++i ) { vec.push_back(i+1); }
    int period = 3;
    int array_size = vec.size();
    array_size-=period;

    //first = vec.begin();
    //last = vec.begin() + period;
    //sum = 0;
    //transform( first, last, back_inserter(m_vec), Sum<int>(first, last) );//エラー

    for(int i=0; i < array_size; ++i) {
        sum = 0;
        if (i < period) {
            sum = 0;
        } else {
            first = vec.begin() + i; last = vec.begin() + i + period;
            sum = Sum<int>( first, last );
            //sum = MovingAve<int, vector<int>::iterator >( first, last );//エラー
        }
        m_vec.push_back(sum);
    }
    copy(m_vec.begin(), m_vec.end(), ostream_iterator<int>(cout, "\n"));
    return 0;
}

επιστημη [E-Mail] [HomePage] 2009/10/12(月) 00:22:50
よくわかんないけど、要はズラしながら部分和を取りたいのね。

#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>

int main() {
    std::vector<int> vec, m_vec;
    for( int i = 0; i<10 ;++i ) { vec.push_back(i+1); }
    int period = 3;
    int array_size = vec.size() - period;

    std::vector<int>::iterator first = vec.begin();
    std::vector<int>::iterator last = vec.begin(); 
    std::advance(last,period);
    for ( int i = 0; i < array_size; ++i ) {
        m_vec.push_back(std::accumulate(first, last, 0));
        ++first; ++last;
    }
    std::copy(m_vec.begin(), m_vec.end(), std::ostream_iterator<int>
(std::cout, "\n"));
    return 0;
}

Milt Jackson 2009/10/12(月) 01:03:05
επιστημη さんありがとございます、
>よくわかんないけど、要はズラしながら部分和を取りたいのね。
若干異なりますが、その通りです(部分集合の要素数がperiod より少ない場合は0 で埋
めたいですが、それは大きな問題ではありません)
std::accumulate ですか、知りませんでした、コードが短く解りやすくなりました。

ところで、私の書いたごみのようなコードですが、
MovingAve(Iterator first = MovingAve(), Iterator last = MovingAve()) :
first_(first), last_(last) {}
↓変更
MovingAve(Iterator first, Iterator last) : first_(first), last_(last) {}

transform( first, last, back_inserter(m_vec), Sum<int>(first, last) );//エラー
↓変更
transform( first, last, back_inserter(m_vec), MovingAve<int,
vector<int>::iterator >() );

このように、コンストラクタとtranform を変更するのですが
error C2512: 'MovingAve<T,Iterator>::MovingAve' : クラス、構造体、共用体に既定の
コンストラクタがありません。
となってしまいます。
私の考えでは
MovingAve<int, vector<int>::iterator >()
この() の部分に
first とlast が代入されるという認識なのですが、間違ってますでしょうか?

επιστημη [E-Mail] [HomePage] 2009/10/12(月) 01:54:26
...ごめん、MovingAveとやらに求められる挙動がわかんない。
コンストラクト時に何を与え、operator()で何を返したいのでしょうか?

Milt Jackson 2009/10/12(月) 05:30:21
すみません説明不足で、このようなことがしたいのですが、可能でしょうか?

transform( first, last, back_inserter(m_vec), ここでMovingAve の@→@´戻り値として
部分和を得たい。 );

@T operator()(Iterator first, Iterator last);
↓
@´
template <class T, class Iterator>
T MovingAve<T, Iterator>::operator()(Iterator first, Iterator last)
{
    T sum = 0;
    while ( first_ != last_ ) {
        sum+=*first_;
        ++first_;
    }
    return sum;
}

Milt Jackson 2009/10/12(月) 05:53:05
補足します
/** @brief operator() を使用し部分和を求める
  * @param[in] Iterator first 求値したい範囲の先頭を指し示す
  * @param[in] Iterator last 求値したい範囲の終端を指し示す
  * @return 部分和を返却
  */
template <class T, class Iterator>
T MovingAve<T, Iterator>::operator()(Iterator first, Iterator last)
{
    T sum = 0;
    while ( first_ != last_ ) {
        sum+=*first_;
        ++first_;
    }
    return sum;
}

Milt Jackson 2009/10/12(月) 06:35:56
すみません修正です変数名のアンダーバーは要りませんでしたというか、在ると
セマンティクス的に間違ってます。
/** @brief operator() を使用し部分和を求める
  * @param[in] Iterator first 求値したい部分範囲の先頭を指し示す
  * @param[in] Iterator last 求値したい部分範囲の終端を指し示す
  * @return 部分和を返却
  */
template <class T, class Iterator>
T MovingAve<T, Iterator>::operator()(Iterator first, Iterator last)
{
    T sum = 0;
    while ( first != last ) {
        sum+=*first;
        ++first;
    }
    return sum;
}

tetrapod 2009/10/12(月) 08:22:36
> first とlast が代入されるという認識なのですが、間違ってますでしょうか?
間違い。
どこからどういう発想が出てきたのかよくわからないが、コンパイラは神ではないので
ソースコードを字面どおりに解釈するだけであり
transform( first, last, back_inserter(m_vec), 
MovingAve<int,vector<int>::iterator >() );
4個目の引数は MovingAve というクラスの一時オブジェクトを生成している、
その際 () 指定で引数なしコンストラクタを呼んでいると解釈する。

STL アルゴリズムの使い方の理解法。とりあえず C++ ソースの <algorithm> を見る。
たいてい <algorithm> の中からさらに別のファイルを呼んでいるので追いかける。
そうすると、数個追っかけると今使いたい <algorighm> 関数のソースが見られる。
4引数 transform であれば
oit transform(iit top, iit bot, oit result, unaryop op) {
 for (; top!=bot; ++top, ++result) *result = op(*top);
 return result;
}
だから algorithm 中で繰り返し何度も unaryop op が呼ばれるわけだ。
ここで op に渡されるのは既に iterator ではないわけで
<algorithm> 系関数の中で使われる unary/binary operator にしたいのであれば
T MovingAve<T, Iterator>::operator()(Iterator first, Iterator last)
では不適合

逆に first last 両方を渡してほしい関数を作りたいのであれば
その関数は transform や copy や accumulate 等と同格、
つまり algorithm 関数を自作することになる。

あと iterator を引数に受け取る関数は & 参照にしないほうがいいぞ。
http://homepage1.nifty.com/MADIA/vc/vc_bbs/200711/200711_07110006.html

Milt Jackson 2009/10/12(月) 16:53:21
[[解決]]
tetrapod さん大変よく分かりました、ありがとうございます。

http://www.kab-studio.biz/Programing/Codian/STL/02.html
ここにtransform の解説として
std::transform() は、関数オブジェクトを使用しないと使えないアルゴリズムのひとつ
です。このアルゴリズムは、第1・2引数に渡された配列を第4引数の関数オブジェクト
へと渡して、その結果を第3引数の配列へと格納するという機能を持っています。つまり
「配列を関数オブジェクトに掛ける」という機能のみを持ったアルゴリズムということで
すね。

この文を読んで、勝手に解釈し「第1・2引数に渡された配列・・・」これを
第4引数の関数オブジェクトへ渡せばいいという、頓珍漢なことをやっていました。

古いスレッドには追加発言できません。