2013-05-15 18 views
5

私は加速されたC++で自分のやり方を進めています&がExで問題を起こしました。 10.2 質問には、前の章のメジアン関数を書き換えることが含まれているため、ベクトルまたは組み込み配列で中央値を呼び出すことができます。中央値関数は、任意の算術型のコンテナも許可する必要があります。テンプレートでエラー:一致する関数呼び出しがありません

は、私は以下の中央値は、詳細には2本の電話をかけることはできません - 私は

No matching function for call to 'median' 

私はテンプレートを使用した場合の種類は、コンパイル時に知られるべきであることを、いくつかの研究から集まるエラーメッセージが表示されます。これが根本的な問題かもしれませんか?何らかの形で型をテンプレート引数として渡す方法はありますか?ここで

は、これまでの私のコードです:

#include <iostream> 
#include <vector> 
#include <stdexcept> 
#include <algorithm> 
#include <cstddef> 

using namespace std; 

template <class Iterator, class Type> 
Type median(Iterator begin, Iterator end) 
{ 
    vector<Type> vec(begin,end); 
    typedef typename vector<Type>::size_type container_sz; 
    container_sz size = vec.size(); 

    if (size == 0) { 
     throw domain_error("median of an empty vector"); 
    } 

    sort(vec.begin(), vec.end()); 

    container_sz mid = size/2; 
    return size % 2 == 0 ? (vec[mid] + vec[mid - 1])/2 : vec[mid]; 
} 

int main() 
{ 
    vector<int> grades; 

    for (int i = 0; i != 10; ++i){ 
     grades.push_back(i); 
    } 

    const int int_array[] = {2, 9, 4, 6, 15}; 
    size_t array_size = sizeof(int_array)/sizeof(*int_array); 

    cout << median(int_array, int_array + array_size) << endl; //error here: Semantic Issue, No matching function for call to 'median' 
    cout << median(grades.begin(), grades.end()) << endl;  //error here: Semantic Issue, No matching function for call to 'median' " 

    return 0; 
} 
+1

とは対照的に、また、一方がmedian<int>(grades.begin(), grades.end())を呼び出す必要があり等級= {0、1、2、3、4 、5,6,7,8,9} 'と' auto size = vec.size(); '(つまり、typedefを取り除く)の3つです。また、 'endl'を' "\ n" 'に置き換えることもできます。 –

+0

ファーストパスリーダーにとっては、コンパイル時エラーの原因となる行(*があれば*両方*を含む)にコメント( '// <== error here'など)を付けてください。つまり、 'Type'テンプレートパラメータは、あなたが作る呼び出しから推測することはできません。これは最終的にはコアの問題です。私は、標準ライブラリ提供のテンプレート['iterator_traits'](http://en.cppreference.com/w/cpp/iterator/iterator_traits)はあなたの問題に対するきれいな解決策かもしれないと思います。 – WhozCraig

+0

完全なエラーメッセージを含めてください。これは、通常、関数呼び出しでどの型を推測するかを示します。実際の予測型と比較することができます。 –

答えて

3

あなたのエラーが提供引数では不可能であるTypeの控除に根ざしています。あなたは、次のように標準ライブラリのクラスiterator_traitsを使用して、これを行うをすることができます

template < 
    class Iterator, 
    class Type = typename std::iterator_traits<Iterator>::value_type> 
Type median(Iterator begin, Iterator end) 
{ 
    vector<Type> vec(begin,end); 

    typedef typename vector<Type>::size_type container_sz; 

    container_sz size = vec.size(); 

    if (size == 0) { 
     throw domain_error("median of an empty vector"); 
    } 

    sort(vec.begin(), vec.end()); 

    container_sz mid = size/2; 

    return size % 2 == 0 ? (vec[mid] + vec[mid - 1])/2 : vec[mid]; 
} 

をクラスiterator_traitsは、それが実際よりももう少し複雑(反復され、それがまともであるかを決定するために提供イテレータ型を解剖します概要)。動作の詳細については、class iterator_traitsのドキュメントを参照してください。イテレータの値の型を決定する最も簡単なメカニズムです。

注:あなたもこれを行うことができ、デフォルトのテンプレートパラメータType宣言の意図しないバイパスを確保しないために:

template <class Iterator> 
typename std::iterator_traits<Iterator>::value_type median(Iterator begin, Iterator end) 
{ 
    if (begin == end) 
     throw domain_error("median of an empty vector"); 

    typedef typename std::iterator_traits<Iterator>::value_type Type; 
    std::vector<Type> vec(begin,end); 
    sort(vec.begin(), vec.end()); 

    typename std::vector<Type>::size_type mid = vec.size()/2; 
    return vec.size() % 2 == 0 ? (vec[mid] + vec[mid - 1])/2 : vec[mid]; 
} 

その少し密集し、中間原料のほとんどをスローしていますが、凝視場合あなたはそれがどのように動作するかを理解し、テンプレートパラメータリストを減らして、あなたが本当に気にしている1つのものだけを使用するようにします。 Iteratorタイプです。これは、関数に提供するパラメータによって簡単に導き出されます。

+0

私は問題の著者の解決策へのリンクで上記のコメントを投稿しました(https://github.com/bitsai/book-exercises/blob/master/Accelerated%20C%2B%2B/chapter10/10-2.hpp)。 ) 私が言及したように、あなたのソリューションは完璧に見えますが、私はそれを見逃すことはありません。 – Octave1

+0

@ Octave1同様に。それが理にかなってほしい。 – WhozCraig

+0

申し訳ありませんが、最初のコメントはすぐに投稿されました。今すぐ編集されました。答えをありがとう。 iterator_traitsは役に立つと思います。 私が理解していないことは、著者の解答は、与えられたイテレーターの引数から型を導き出すことによって、私と同じエラーを出すようです。何か案は? – Octave1

4

この問題に取り組む最も良い方法は、一般に上記のようにiterator_traitsを使用することです。しかし、特定の質問10.2を書籍(Iterator_traitナレッジは想定していません)に答えるには、次のように進めることができます。 - クラスIteratorの代わりにクラスの型を最初に指定する必要があります。あなたはC++ 11を使用している場合は、ベクトル 'とベクトルを初期化することができるmedian(grades.begin(), grades.end())

#include <iostream> 
#include <vector> 
#include <stdexcept> 
#include <algorithm> 
#include <cstddef> 

using namespace std; 

template <class Type, class Iterator>  //the order allows the second template parameter type to be deduced (Iterator)           
Type median(Iterator begin, Iterator end) //while requiring you still provide the first type 
{ 

    vector<Type> vec(begin,end); 

    //typedef typename vector<Type>::size_type container_sz; 
    //container_sz size = vec.size() 
    auto size = vec.size(); 

    if (size == 0) { 
     throw domain_error("median of an empty vector"); 
    } 

    sort(vec.begin(), vec.end()); 

    //container_sz mid = size/2 
    auto mid = size/2; 

    Type ret = size % 2 == 0 ? (vec[mid] + vec[mid - 1])/2 : vec[mid]; 

    return ret; 
} 


int main() 
{ 

    vector<int> grades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 

    const int int_array[] = {2, 9, 4, 6, 15}; 

    size_t array_size = sizeof(int_array)/sizeof(*int_array); 

    cout << median<int>(int_array, int_array + array_size) << endl; //must provide int here, in order to give the template the return type at compile time 
    cout << median<int>(grades.begin(), grades.end()) << endl; 


return 0; 

}

関連する問題