Effective C++

【Effective C++(7)】模板与泛型编程

2018-01-08  本文已影响20人  downdemo

41 了解隐式接口和编译期多态

class Widget {
public:
    Widget();
    virtual ~Widget();
    virtual std::size_t size() const;
    virtual void normalize();
    void swap(Widget& other);
    ...
};
void doProcessing(Widget& w)
{
    if (w.size() > 10 && w != someNasyWidget) {
        Widget temp(w);
        temp.normalize();
        temp.swap(w);
    }
}
template<typename T>
void doProcessing(T& w)
{
    if (w.size() > 10 && w != someNasyWidget) {
        T temp(w);
        temp.normalize();
        temp.swap(w);
    }
}
class Widget {
public:
    Widget();
    virtual ~Widget();
    virtual std::size_t size() const;
    virtual void normalize();
    void swap(Widget& other);
    ...
};
template<typename T>
void doProcessing(T& w)
{
    if (w.size() > 10 && w != someNasyWidget) {
       ...

42 了解typename的双重意义

template<class T> class Widget;
template<typename T> class Widget;
// 打印容器第二个元素,该代码不合法,后续说明原因
template<typename C>
void print2nd(const C& container)
{
    if(container.size() >= 2)  {
        C::const_iterator iter(container.begin());
        ++iter;
        int value = *iter;
        std::cout << value;
    }
}
template<typename C>
void print2nd(const C& container)
{
    C::const_iterator* x;
    ...
}
// 合法的代码
template<typename C>
void print2nd(const C& container)
{
    if (container.size() >= 2)  {
        typename C::const_iterator iter(container.begin());
        ...
template<typename T>
class Derived: public Base<T>::Neted  { // base class list中不允许typename
public:
    explicit Derived(int x) : Base<T>::Nested(x) // 成员初值列中不允许typename
    {
        typename Base<T>::Nested temp; // 除了前两种情况嵌套从属名称都得加上typename
        ...
    }
    ...
};
template<typename IterT>
void workWithIterator(IterT iter)
{
    typename std::iterator_trains<IterT>::value_type temp(*iter);
    ...
}
// 加上typedef
template<typename IterT>
void workWithIterator<IterT iter)
{
    typedef typename std::iterator_trains<IterT>::value_type value_type;
    value_type temp(*iter);
    ...
}

43 学习处理模板化基类内的名称

template<typename T>
class A {
public:
    void f() {
        ...
    }
    ...
private:
    ...
};

template<typename T>
class B : public A<T> {
public:
    void useF(){
        f();  // 调用基类函数,编译错误,编译器无法在模板化基类中查找f
    }
    ...
private:
    ...
};
// 在base class函数调用动作之前加上this->
template<typename T>
class B : public A<T> {
public:
    void useF(){
        this->f();
    }
    ...
};

// 使用using声明式
template<typename T>
class B : public A<T> {
public:
    using A<T>::f;
    void useF(){
        f();
    }
    ...
};

// 明确指出被调用的函数位于base class内,这种做法的缺点是如果调用的是虚函数会关闭动态绑定
template<typename T>
class B : public A<T> {
public:
    void useF() {
        A<T>::f();
    }
    ...
};

44 将与参数无关的代码抽离templates

// A是一个n * n矩阵,元素是类型为T的对象
template <typename T, int n>
class A {
public:
    void f();
};

// 下面会实例化两份f,引起代码膨胀
A<double, 5> a;
a.f();
A<double, 10> b;
b.f();
template <typename T>
class A {
protected:
    void f(int n);
};

template <typename T, int n>
class B : private A<T> { // 基类只是为了帮助派生类实现而非is-a关系,所以用private继承
private:
    using A<T>::f;
public:
    void f() { this->f(n); }
};
template <typename T>
class A {
protected:
    A(int n, T* pMem) : number(n), pData(pMem) {}
    void setDataPtr(T* ptr) { pData = ptr; }
    ...
private:
    int number;
    T* pData;
};
template <typename T, int n>
class B : private A<T> {
public:
    B() : A<T>(n, data) {}
    ...
private:
    T data[n*n];
};
template <typename T, int n>
class B : private A<T> {
public:
    B() : A<T>(n, 0), pData(new T[n*n])
    { this->setDataPtr(pData.get()); }
    ...
private:
    boost::scoped_array<T> pData;
};

45 运用成员函数模板接受所有兼容类型

class Top { ... }; 
class Middle : public Top { ... }; 
class Bottom : public Middle { ... }; 
Top* pt1 = new Middle;        // 将Middle*转换成Top* 
Top* pt2 = new Bottom;        // 将Bottom*转换成Top* 
const Top* pct2 = pt1;        // 将Top*转换成const Top*
template<typename T>
class SmartPtr {
public:
    explicit SmartPtr(T* realPtr);
    ...
};
SmartPtr<Top> pt1 = SmartPtr<Middle>(new Middle);
SmartPtr<Top> pt2 = SmartPtr<Bottom>(new Bottom);
SmartPtr<const Top> pct2 = pt1;
template<typename T>
class SmartPtr {
public:
    template<typename U>   // member template
    SmartPtr(const SmartPtr<U>& other);  // 为了生成copy构造函数
    ...
};
template<typename T>
class SmartPtr {
public: 
    template<typename U>
    SmartPtr(const SmartPtr<U>& other)
    : heldPtr(other.get()) { ... }
    T* get() const { return heldPtr; }
    ...
private:
    T* heldPtr; // 该智能指针持有的原始指针
};
template<class T>
class shared_ptr {
public:
    shared_ptr(shared_ptr const& r); // copy构造函数

    template<class Y>
    shared_ptr(shared_ptr<Y> const& other); // 泛化copy构造函数

    shared_ptr& operator= (shared_ptr const& r); // copy assignment

    template<class Y>
    shared_ptr& operator= (shared_ptr<Y> const& r); // 泛化copy assignment
};

46 需要类型转换时请为模板定义非成员函数

template<typename T>
class Rational {
public:
    Rational(const T& numerator = 0, const T& denominator = 1);
    const T numerator() const;
    const T denominator() const;
    ...
};
template<typename T>
const Rational<T> operator* (const Rational<t>& lhs, const Rational<t>& rhs)
{
    ...
}
Rational<int> oneHalf(1,2);
Rational<int> result = oneHalf * 2; // 编译错误
template<typename T> 
class Rational { 
public: 
    ...
    // class template内,template名称就是template和其参数的简写
    // 因此不必写Rational<T>,简写节省时间而且代码更干净
    friend
    const Rational operator* (const Rational& lhs, const Rational& rhs);
};

template<typename T> 
const Rational<T> operator*(const Rational<T>& lhs, const Rational<T>& rhs)
{ ... }
template<typename T>
class Rational {
public:
    ...
    // Rational<T>都简写为Rational
    friend
    const Rational operator* (const Rational& lhs, const Rational& rhs)
    {
        return Rational(lhs.numerator() * rhs.numerator(),
            lhs.denominator() * rhs.denominator());
    }
};
template<typename T> class Rational;

template<typename T>
const Rational<T> doMultiply (const Rational<T>& lhs, const Rational<T>& rhs)
{
    return Rational<T>(lhs.numerator() * rhs.numerator(),
        lhs.denominator() * rhs.denominator()); 
}

template <typename T>
class Rational {
public:
    ...
    friend
    const Rational<T> operator*(const Rational<T>& lhs, const Rational<T>& rhs)
    { return doMultiply(lhs, rhs); }
    ...
};

47 请使用traits classes表现类型信息

template<typename IterT, typename DistT>  
void advance(IterT& iter, DistT d); // 将迭代器向前移动d个单位,d<0则向后移动
struct input_iterator_tag {};   
struct output_iterator_tag {};   
struct forward_iterator_tag : public input_iterator_tag {};   
struct bidirectional_iterator_tag : public forward_iterator_tag {};   
struct random_iterator_tag : public bidirectional_iterator_tag {};  
template<typename IterT, typename DistT>  
void advance(IterT& iter, DistT d) {  
    if (iter is a random_access_iterator) 
    { iter += d; } //针对random_access迭代器使用迭代器算术运算  
    else {
        if (d >= 0) { while (d--) ++iter; }
        else { while (d++) --iter; }  
    }
}
template < ... >
class deque {
public:
  class iterator {
  public:
    typedef random_access_iterator_tag iterator_category;
    ...
  };
  ...
};
template < ... >
class list {
public:
  class iterator {
  public:
    typedef bidirectional_iterator_tag iterator_category;
    ...
  };
  ...
};
template<typename IterT>
struct iterator_traits {
  typedef typename IterT::iterator_category iterator_category;
  ...
};
template<typename IterT>
struct iterator_traits<TierT*> {
    typedef random_access_iterator_tag iterator_category;
    ...
};
template<typename IterT, typename DistT>  
void advance(IterT& iter, DistT d)  
{
    if (typeid(typename std::iterator_traits<IterT>::iterator_category)
        == typeid(std::random_access_iterator_tag))  
    ...
}
template <typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d, random_access_iterator_tag)
{
    iter += d;
}

template <typename IterT, typename DistT>
void doAdcance(IterT& iter, DistT d, bidirectionl_iterator_tag)
{
    if(d >= 0) { while (d--) ++iter; }
    else { while (d++) --iter; }
}

template <typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d, input_iterator_tag)
{
    if (d < 0) {
        throw out_of_range("Negative distance");
    }
    while (d--) ++iter;
}
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{
    doAdvance(
    iter, d,
    typename
    std::iterator_traits<IterT>::iterator_category()
    );                            
}

48 认识template元编程

template<typename Iter, typename DistT>
void advance(IteT& iter,DistT d)
{
    if(typeid(typename std::iterator_traits<IterT>::iterator_category)
        == typeid(std::random_access_iterator_tag)) {
        iter += d;
    }
    else {
        if(d >= 0){ while(d--) ++iter; }
        else { while(d++) --iter; }
    }
}
std::list<int>::iterator iter;
...
advance(iter, 10); // 移动iter向前走10个元素
// 上述实现无法通过编译
// 下面这一版的advance便是针对上述调用产生的
// 将template参数iterT和DistT分别替换为iter和10的类型之后得到
void advance(std::list<int>::iterator& iter, int d)
{
    if (typeid(typename std::iterator_traits<std::list<int>::iterator>::iterator_category)
        ==typeid(std::random_access_iterator_tag)) {
        iter += d; // 错误
    }
    else {
        if(d >= 0) { while(d--) ++iter; }
        else { while(d++) --iter; }
    }
}
template<unsigned n>
struct Factorial {
    enum { value = n * Factorial<n-1>::value };
};
template<>
struct Factorial<0>{ // 特殊情况,Factorial<0>的值是1
    enum { value = 1 };
};
// 可以这样使用Factorial
int main()
{
    std::cout << Factorial<5>::value; // 印出120
    std::cout << Factorial<10>::value; // 印出3628800
}
上一篇下一篇

猜你喜欢

热点阅读