bla_bla_bla
bla_bla_bla

Reputation: 15

Parametrized traits c++

I am learning templates from book: C++ Templates, The complete guide ( Vandevoorde, Josuttis). On chapter 15.1.3. is the following example:

// 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 

As is often the case, we can introduce convenience functions to simplify the interface:

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); 
} 

This is point, where I got lost. Can anybody explain how the second interface function works, why is it good idea to use it, when is it useful and how to call it?

thanks!

Upvotes: 0

Views: 103

Answers (2)

Richard Hodges
Richard Hodges

Reputation: 69892

To Specifically answer the question, the second form allows you to select the traits class at the call site, eg:

#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;
}

expected output:

45
90

Upvotes: 1

Kerrek SB
Kerrek SB

Reputation: 477160

The point is that function templates allow for the deduction of template parameters from the function call expression, whereas there is no such analogue for class templates.

If you only had the class template, you would need to spell out the template parameters yourself:

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

By complementing the class template with a helper function template, we can let template argument deduction figure the type out:

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

This is a common pattern. Examples in the standard library are make_pair, make_tuple, make_optional, make_move_iterator, and make_reverse_iterator. For example:

auto x = std::make_optional(10);

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

A more striking example is 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 each case, the return type depends in some way on a class template specialization, but the type-deducing helper function template allows us to never have to say the class template name at all.

Upvotes: 1

Related Questions