2016-09-15 11 views
3

異なるSTLコンテナの合計を得る2つのテンプレート関数を設定します.1つはリストとベクトル用、もう1つはマップ用です。関数テンプレートのオーバーロードと明示的な特殊化

2番目のテンプレート関数定義のコメント行(1)と(2)を参照してください。コメントアウトされたコード(= 2)も正常に動作するので、どの構文が推奨されているか分かりません。

また、各メソッドはどのように呼び出されましたか(私のコメントでは私は適切に推測しましたか)? (1)は関数テンプレートであり、キーワード 'template'の後ろにtypename引数がないため、オーバーロードが不十分であるようです。つまり、関数テンプレートのオーバーロードとしてメソッドを呼び出すためには、(1)と組み合わせてのようにする必要があります。彼らの正式な名前を教えてください。具体的なタイプの場合

template <typename T> // T : container 
double Sum(const T &l) // get Container 
{ 
    double sum = 0; 
    T::const_iterator i; 
    for (i = l.begin(); i != l.end(); ++i) { sum += *i; } 
    return sum; 
} 

template <> // get container 
double Sum(const map<string, double> &m) // (1) function template overloading 
// double Sum<map<string, double> >(const map<string, double> &m) // (2) explicit specialization 
{ 
    double sum = 0; 
    map<string, double>::const_iterator i; // obtain Iterator from Container 
    for (i = m.begin(); i != m.end(); i++) { sum += i->second; } // sum. ('first' is index, 'second' is data) 
    return sum; 
} 
+0

いいえ(1)はテンプレートです(2)は和の過負荷である。 – coincoin

答えて

1

どちらが最初の1 LETコンパイラ明示的な特殊構文

  • template <> double Sum(const map<string, double> &m);

  • template <> double Sum<map<string, double> >(const map<string, double> &m)

あるが、パラメータを導き出します。

template <typename T> std::string getNameType(); 

template <> std::string getNameType<int>() { return "int"; } 

または

template <typename T> void foo(T); 

template <typename T> void foo(T*); // overload, not specialization 

//template <> void foo(int*); // Error: do you mean T = int for foo(T*) or T = int* for foo(T) 

template <> void foo<int*>(int*); // specialize foo(T) 
template <> void foo<int>(int*); // specialize foo(T*) 

を特化するテンプレート機能明確にするためにため代わりに専門のオーバーロードを使用することが一般的に優れているとして、コンパイラは、すべてのテンプレートパラメータを推測することができない場合に、第2が必要です関数のため、あなたの例:

+0

詳細と完全な回答をいただきありがとうございます。それは本当に役立ちます。 –

0

、あなたはおそらく、単に非テンプレートオーバーロードを定義する方がいいでしょう:

double Sum(const std::map<std::string, double> &m) // (1) function template overloading 
// double Sum<map<string, double> >(const map<string, double> &m) // (2) explicit specialization 
{ 
    double sum = 0; 
    std::map<std::string, double>::const_iterator i; // obtain Iterator from Container 
    for (i = m.begin(); i != m.end(); i++) { sum += i->second; } // sum. ('first' is index, 'second' is data) 
    return sum; 
} 

テンプレートは、一般的な機能のために、より便利です。

// 
// sum any map's arithmetic mapped values 
// 
template<class K, class V, class C, class A> 
typename std::map<K, V, C, A>::mapped_type 
Sum(const std::map<K, V, C, A> &m) // (1) function template overloading 
{ 
    using map_type = std::map<K, V, C, A>; 
    using mapped_type = typename map_type::mapped_type; 
    using const_iterator = typename map_type::const_iterator; 
    mapped_type sum = 0; 
    const_iterator i; // obtain Iterator from Container 
    for (i = m.begin(); i != m.end(); i++) { sum += i->second; } // sum. ('first' is index, 'second' is data) 
    return sum; 
} 

.. (C++ 14)...

namespace notstd { 
    template<class...> 
    using void_t = void; 
} 

template< class, class = notstd::void_t<> > 
struct supports_mapped_type : std::false_type { }; 

template< class T > 
struct supports_mapped_type<T, notstd::void_t<typename T::mapped_type>> : std::true_type { }; 

template< class, class = notstd::void_t<> > 
struct supports_const_iterator : std::false_type { }; 

template< class T > 
struct supports_const_iterator<T, notstd::void_t<typename T::const_iterator>> : std::true_type { }; 

template<class T> static constexpr bool IsMaplike = supports_mapped_type<T>() and supports_const_iterator<T>(); 

template<class MapLike, 
std::enable_if_t< 
IsMaplike<MapLike> and std::is_arithmetic<typename MapLike::mapped_type>() 
>* = nullptr> 
typename MapLike::mapped_type 
Sum(const MapLike &m) // (1) function template overloading 
{ 
    using map_type = MapLike; 
    using mapped_type = typename map_type::mapped_type; 
    using const_iterator = typename map_type::const_iterator; 
    mapped_type sum = 0; 
    const_iterator i; // obtain Iterator from Container 
    for (i = m.begin(); i != m.end(); i++) { sum += i->second; } // sum. ('first' is index, 'second' is data) 
    return sum; 
} 

これは今幸せに合計します:あなたのコードはOKのようだとして

std::unordered_map<std::string, int>、および std::map<std::string, int>

なく std::map<int, std::string>

+0

私はあなたの答えから多くのことを知るようになりました。どうもありがとうございました! –

+0

@ DongkyuChoiそれは考えです。あなたは歓迎です:) –

0

私は完全に、あなたの質問を理解していなかったが、私は」答えようとする。関数のオーバーロードは、同じ名前で異なる引数の型を持つ複数の関数を手動で記述するときのアプローチです。たとえば:

template <typename T> 
double Sum(const T &l) //... 

とテンプレートの特殊化:

template <> 
double Sum(const map<string, double> &m) //... 

優れている、あなたの例では

double Sum(const std::vector<double>& l) { 
    //... 
} 

double Sum(const std::list<double>& l) { 
    //... 
} 

double Sum(const std::deque<double>& l) { 
    //... 
} 

あなたは関数テンプレートを書きましたか?あなたの状況によって異なります。関数のオーバーロードでコードを自分で書くべきですが、テンプレートの場合はコンパイラがそれを行います。

たとえば、あなたの一般的なケーステンプレートはvectorlistqueuedequeとさえテンプレート作成の瞬間のために存在しないかもしれ互換性のある他の容器のために動作します。コンパイラは、テンプレートをインスタンス化するために使用されるタイプのコードのみを生成します。互換性のない型でインスタンス化しようとすると、コンパイルエラーが発生します。 map<string, double>(これは一般的なケースのテンプレートでは無効です)でインスタンス化する場合のみ、コード生成のために特殊化が選択されるため、コンパイルは成功します。

@RichardHodgesに記載されているように、専門性はあなたの場合には過度のものかもしれません。テンプレート以外のオーバーロードで十分です。第二に、あなたが明示的にしているのに対し、

+0

あなたの説明は本当に分かりやすいものでした。ご回答どうもありがとうございました! –

関連する問題