参数化特征 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_pair
、make_tuple
、make_optional
、make_move_iterator
和 make_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
我正在从书中学习模板: 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_pair
、make_tuple
、make_optional
、make_move_iterator
和 make_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