2016-05-15 28 views
2

"Accelerated C++"の演習を行っています。コンパイラが関数テンプレートの型を推論する方法について理解していない動作がいくつか見つかりました。練習10-2では、ベクトルまたは組み込み配列に算術型のリストの中央値を計算できるテンプレート関数を記述するように求められています。私が欲しかったので、もしテンプレート関数内の逆参照されたイテレータから型を推測する

#ifndef median_hpp 
#define median_hpp 

#include <algorithm> 
#include <stdexcept> 
#include <vector> 

using std::domain_error; 
using std::sort; 
using std::vector; 

template <class T, class Iterator> 
T median(Iterator begin, Iterator end) { 

    //check if the container is empty 
    if (begin == end) 
    throw domain_error("median of an empty container"); 

    //create a vector with the same type as the container 
    //and copy the container contents into it 
    vector<T> temp; 

    for (; begin != end; ++begin) 
    temp.push_back(*begin); 

    //sort the temporary vector, and compute and return the median 
    sort(temp.begin(), temp.end()); 

    size_t mid = temp.size()/2; 

    T ret = (temp.size() % 2 == 0) 
    ? (temp[mid] + temp[mid - 1])/2 
    : temp[mid]; 

    return ret; 
} 

#endif /* median_hpp */ 

:私はつまり、私は「median.hpp」と呼ばれる以下のファイルを作成し、2つの反復子間の中央コンテナ値を計算して返すテンプレート関数を必要とするこの問題に例のソリューションつまずいこの機能は、私はこのような前述のテンプレート機能を使用することになり、両方のコンテナタイプのために働くことを実証するために、たとえば、配列やベクトルの中央値を計算する:私は理解していない理由のために、しかし

#include <iostream> 
#include <vector> 
#include "median.hpp" 

using std::vector; 
using std::cout; 
using std::cin; 
using std::endl; 

int main() 
{ 

    int arr[] = {12,2,4,1,4,56,1}; 

    const size_t nData = sizeof(arr)/sizeof(*arr); 
    vector<double> v(arr, arr + nData); 

    cout << median(v.begin(),v.end()) << endl; 
    cout << median(arr, arr + nData) << endl; 

    return 0; 
} 

を、次のエラーが表示されます。

'median'への呼び出しで一致する関数がありません...候補テンプレートが無視されました:テンプレート引数 'T'を推論できませんでした

私の知る限り、コンパイラは、逆参照されたイテレータからの "T"の型。私は知りたいです

A.これはなぜ起こっていますか?

B.この問題を解決するうまい方法はありますか?

答えて

1

コンパイラはIteratorを推測できますが、Tは推測できません。それはあなたがそれに渡すものからTを推論する方法を言いませんからです。 Iterator?未知のIteratorタイプから、が実際に何であるか知らないと、どのようにTが何であるかを知ることができますか?コンパイラは単にそのことを知らない。しかし

、あなたはIteratorは、実際のイテレータ型であり、ほとんどのイテレータは戻ってあなたがに関するすべての何か

template <class Iterator, class T = typename std::iterator_traits<Iterator>::value_type> 
T median(Iterator begin, Iterator end) { ... } 

などの情報を行うことができ T含まれる型への型エイリアスを持っているという知識を持っているので、これは、例えば、 this std::vector referenceこれは、ベクトルの iteratorタイプが random access iteratorであり、 value_typeと記載されており、それが std::iterator_traitsからどのように見つかるかを示しています。

std::iterator_traitsは、std::vectorで与えられるランダムアクセスイテレータだけでなく、すべての標準イテレータに使用することができます。

1

medianにはTという引数がないため、コンパイラはその型を推論できません。

ソリューション:

template <class Iterator, class T = typename std::iterator_traits<Iterator>::value_type> 
T median(Iterator begin, Iterator end) { 
    // .... 
} 

live example

関連する問題