0

Ich lerne Vorlagen aus Buch: C++ Vorlagen, Der vollständige Leitfaden (Vandevoorde, Josuttis). In Kapitel 15.1.3. Beispiel hierfür ist die folgende:Parametrisierte Eigenschaften C++

// traits/accum5.hpp 

#ifndef ACCUM_HPP 
#define ACCUM_HPP 

#include "accumtraits4.hpp" 

template <typename T, 
      typename AT = AccumulationTraits<T> > 
class Accum { 
    public: 
    static typename AT::AccT accum (T const* beg, T const* end) { 
     typename AT::AccT total = AT::zero(); 
     while (beg != end) { 
      total += *beg; 
      ++beg; 
     } 
     return total; 
    } 
}; 

#endif // ACCUM_HPP 

Wie es oft der Fall, wir Komfortfunktionen einführen können die Schnittstelle zu vereinfachen:

template <typename T> 
inline 
typename AccumulationTraits<T>::AccT accum (T const* beg, 
              T const* end) 
{ 
    return Accum<T>::accum(beg, end); 
} 

template <typename Traits, typename T> 
inline 
typename Traits::AccT accum (T const* beg, T const* end) 
{ 
    return Accum<T, Traits>::accum(beg, end); 
} 

Dies ist Punkt, wo ich habe verloren. Kann jemand erklären, wie die zweite Schnittstellenfunktion funktioniert, warum ist es eine gute Idee, sie zu verwenden, wann ist sie nützlich und wie wird sie aufgerufen?

danke!

+0

OK. Aber was sagt dein Buch? –

+0

sie sagen nur: Wie oft der Fall, können wir Komfortfunktionen einführen, um die Schnittstelle zu vereinfachen das ist es –

Antwort

1

, um speziell die Frage zu beantworten, kann die zweite Form Sie die Züge Klasse an der Aufrufstelle wählen, zB:

#include <vector> 
#include <iostream> 

template<class T> 
struct AccumulationTraits 
{ 
    using AccT = T; 
    static constexpr AccT zero() { return AccT(0); } 
}; 

template <typename T, 
typename AT = AccumulationTraits<T> > 
class Accum { 
public: 
    static typename AT::AccT accum (T const* beg, T const* end) { 
     typename AT::AccT total = AT::zero(); 
     while (beg != end) { 
      total += *beg; 
      ++beg; 
     } 
     return total; 
    } 
}; 

template <typename T> 
inline 
typename AccumulationTraits<T>::AccT accum (T const* beg, 
              T const* end) 
{ 
    return Accum<T>::accum(beg, end); 
} 

template <typename Traits, typename T> 
inline 
typename Traits::AccT accum (T const* beg, T const* end) 
{ 
    return Accum<T, Traits>::accum(beg, end); 
} 



template<class T> 
struct Doubler 
{ 
    struct AccT { 
     AccT(T t) : _t(t) {} 
     operator T() const { return _t; } 
     AccT& operator+=(T t) { _t += (t * 2); return *this; } 
     T _t; 
    }; 
    static constexpr AccT zero() { return AccT(0); } 
}; 

int main() 
{ 
    std::vector<int> v { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

    // first form selects default traits class 
    auto a = accum(&v[0], &v[v.size()]); 
    std::cout << a << std::endl; 

    // second form selects any other traits class 
    auto b = accum<Doubler<int>>(&v[0], &v[v.size()]); 
    std::cout << b << std::endl; 
} 

erwartete Ausgabe:

45 
90 
1

Der Punkt ist, dass Funktionsvorlagen die Ableitung von Template-Parametern aus dem Funktionsaufruf-Ausdruck ermöglichen, während es kein Analogon für Klassen-Templates gibt.

Wenn Sie nur die Klassenvorlage hätten, würden Sie brauchen, um die Vorlage zu buchstabieren Parameter selbst:

int arr_sum = Accum<int>::accum(arr, arr + len); 
//     ^^^^^ 

Durch die Ergänzung der Klassenvorlage mit einer Hilfsfunktion Vorlage können wir Template-Argument Abzug Figur die Art lassen aus:

int arr_sum = accum(arr, arr + len); // Deduces T = int 

Dies ist ein übliches Muster. Beispiele in der Standardbibliothek sind make_pair, make_tuple, make_optional, make_move_iterator und make_reverse_iterator. Zum Beispiel:

auto x = std::make_optional(10); 

// same as: 
std::optional<int> x(10); 

Ein eindrucksvolles Beispiel ist make_reverse_iterator:

auto it = f(); 
auto rit = std::make_reverse_iterator(it); 

// same as: 
std::map<int, std::string>::iterator it = f(); 
std::reverse_iterator<std::map<int, std::string>::iterator> rit(it); 

In jedem Fall hängt der Rückgabetyp in irgendeine Weise auf einer Klasse Template-Spezialisierung, aber die Typ-herzuleiten Helferfunktion Vorlage kann Wir müssen niemals den Namen der Klassenvorlage sagen.

+0

danke! Wäre es möglich, ein Beispiel dafür zu geben, wie die Schnittstelle mit der 2. Option aufgerufen wird? –

+1

@petertutuk: Sicher. Sie können einige Template-Parameter angeben und die übrigen ableiten lassen, so dass Sie sagen können: "accum (Beginn, Ende)". –