参数化特征 C++

Parametrized traits c++

我正在从书中学习模板: C++ 模板,完整指南(Vandevoorde,Josuttis)。 关于第 15.1.3 章。是下面的例子:

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

通常情况下,我们可以引入便利功能来简化界面:

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

这是我迷路的地方。 谁能解释第二个接口函数是如何工作的,为什么使用它是个好主意,什么时候有用以及如何调用它?

谢谢!

重点是函数模板允许从函数调用表达式中扣除模板参数,而 class 模板没有这样的类似物。

如果你只有class模板,你需要自己拼出模板参数:

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

通过用辅助函数模板补充 class 模板,我们可以让模板参数推导计算出类型:

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

这是一个常见的模式。标准库中的示例有 make_pairmake_tuplemake_optionalmake_move_iteratormake_reverse_iterator。例如:

auto x = std::make_optional(10);

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

一个更显着的例子是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);

在每种情况下,return 类型都以某种方式依赖于 class 模板特化,但是类型推导辅助函数模板让我们永远不必说 class 模板名称。

为了具体回答问题,第二种形式允许您 select 调用站点的特征 class,例如:

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

预期输出:

45
90