C++ Templates

【C++ Templates(19)】模板与继承

2018-06-19  本文已影响11人  downdemo

空基类优化(EBCO)

布局原则

#include <iostream>

class Empty {
    using Int = int;  // type alias members don't make a class nonempty
};

class EmptyToo : public Empty {
};

class EmptyThree : public EmptyToo {
};

int main()
{
    std::cout << "sizeof(Empty):      " << sizeof(Empty)
              << '\n';
    std::cout << "sizeof(EmptyToo):   " << sizeof(EmptyToo)
              << '\n';
    std::cout << "sizeof(EmptyThree): " << sizeof(EmptyThree)
              << '\n';
}
Layout of EmptyThree by a compiler that implements the EBCO Layout of EmptyThree by a compiler that does not implement the EBCO
#include <iostream>

class Empty {
    using Int = int;  // type alias members don't make a class nonempty
};

class EmptyToo : public Empty {
};

class NonEmpty : public Empty, public EmptyToo {
};

int main()
{
    std::cout << "sizeof(Empty):    " << sizeof(Empty) << '\n';
    std::cout << "sizeof(EmptyToo): " << sizeof(EmptyToo) << '\n';
    std::cout << "sizeof(NonEmpty): " << sizeof(NonEmpty) << '\n';
}
Layout of NonEmpty by a compiler that implements the EBCO

成员作为基类

template <typename T1, typename T2>
class MyClass {
private:
    T1 a;
    T2 b;
    ...
};
template <typename T1, typename T2>
class MyClass : private T1, private T2 {
};
template <typename CustomClass>
class Optimizable {
private:
    CustomClass info; // might be empty
    void* storage;
    ...
};
template <typename CustomClass>
class Optimizable {
private:
    BaseMemberPair<CustomClass, void*> info_and_storage;
    ...
};
// inherit/basememberpair.hpp

#ifndef BASE_MEMBER_PAIR_HPP
#define BASE_MEMBER_PAIR_HPP

template <typename Base, typename Member>
class BaseMemberPair : private Base {
  private:
    Member member;
  public:
    // constructor
    BaseMemberPair (Base const & b, Member const & m)
     : Base(b), member(m) {
    }

    // access base class data via first()
    Base const& first() const {
        return (Base const&)*this;
    }

    Base& first() {
        return (Base&)*this;
    }

    // access member data via second()
    Member const& second() const {
        return this->member;
    }
    Member& second() {
        return this->member;
    }
};

#endif // BASE_MEMBER_PAIR_HPP

奇异递归模板模式(CRTP)

template <typename Derived>
class CuriousBase {
    ...
};

class Curious : public CuriousBase<Curious> {
    ...
};
template <typename Derived>
class CuriousBase {
    ...
};

template <typename T>
class CuriousTemplate : public CuriousBase<CuriousTemplate<T>> {
    ...
};
template <template<typename> class Derived>
    class MoreCuriousBase {
    ...
};

template <typename T>
    class MoreCurious : public MoreCuriousBase<MoreCurious> {
    ...
};
// inherit/objectcounter.hpp

#include <cstddef>

template <typename CountedType>
class ObjectCounter {
private:
    static std::size_t count;    // number of existing objects
    // before C++17, inline had to be define outside the class template
    // since C++17 could write
    // inline static std::size_t count = 0;

protected:
    // default constructor
    ObjectCounter() { 
        ++count;
    }

    // copy constructor
    ObjectCounter (ObjectCounter<CountedType> const&) {
        ++count; 
    }

    // move constructor
    ObjectCounter (ObjectCounter<CountedType> &&) {
        ++count; 
    }

    // destructor
    ~ObjectCounter() { 
        --count;
    }

public:
    // return number of existing objects:
    static std::size_t live() { 
        return count; 
    }
};

// initialize counter with zero
template <typename CountedType>
size_t ObjectCounter<CountedType>::count = 0;
// inherit/testcounter.cpp

#include "objectcounter.hpp"
#include <iostream>

template <typename CharT>
class MyString : public ObjectCounter<MyString<CharT>> {
  //...
};

int main()
{
    MyString<char> s1, s2;
    MyString<wchar_t> ws;

    std::cout << "num of MyString<char>:    " 
              << MyString<char>::live() << ‘\n';
    std::cout << "num of MyString<wchar_t>: " 
              << ws.live() << '\n';
}

Barton-Nackman Trick

template<typename T>
class Array {
public:
    ...
};

template<typename T>
bool operator== (Array<T> const& a, Array<T> const& b)
{
    ...
}
template<typename T>
class Array {
    static bool areEqual(Array<T> const& a, Array<T> const& b);
public:
    ...
    friend bool operator== (Array<T> const& a, Array<T> const& b)
    {
        return areEqual(a, b);
    }
};
// inherit/wrapper.cpp
class S {
};

template<typename T>
class Wrapper {
private:
    T object;
public:
    Wrapper(T obj) : object(obj) { // implicit conversion from T to Wrapper<T>
    }
    friend void foo(Wrapper<T> const&) {
    }
};

int main()
{
    S s;
    Wrapper<S> w(s);
    foo(w); // OK: Wrapper<S> is a class associated with w
    foo(s); // ERROR: Wrapper<S> is not associated with s
}

operator实现

bool operator!= (X const& x1, X const& x2) {
    return !(x1 == x2);
}
template<typename T>
bool operator!= (T const& x1, T const& x2) {
    return !(x1 == x2);
}
// inherit/equalitycomparable.cpp
template<typename Derived>
class EqualityComparable {
public:
    friend bool operator!= (Derived const& x1, Derived const& x2)
    {
        return !(x1 == x2);
    }
};

class X : public EqualityComparable<X> {
public:
    friend bool operator== (X const& x1, X const& x2) {
    // implement logic for comparing two objects of type X
    }
};

int main()
{
    X x1, x2;
    if (x1 != x2) { }
}

Facade

// inherit/iteratorfacadeskel.hpp

template<typename Derived, typename Value,
    typename Category, typename Reference = Value&, 
    typename Distance = std::ptrdiff_t>
class IteratorFacade {
public:
    using value_type = typename std::remove_const<Value>::type;
    using reference = Reference;
    using pointer = Value*;
    using difference_type = Distance;
    using iterator_category = Category;

    // input iterator interface:
    reference operator *() const { ... }
    pointer operator ->() const { ... }
    Derived& operator ++() { ... }
    Derived operator ++(int) { ... }
    friend bool operator== (IteratorFacade const& lhs,
    IteratorFacade const& rhs) { ... }
    ...

    // bidirectional iterator interface:
    Derived& operator --() { ... }
    Derived operator --(int) { ... }

    // random access iterator interface:
    reference operator [](difference_type n) const { ... }
    Derived& operator +=(difference_type n) { ... }
    ...
    friend difference_type operator -(IteratorFacade const& lhs,
        IteratorFacade const& rhs) { ... }
    friend bool operator <(IteratorFacade const& lhs,
        IteratorFacade const& rhs) { ... }
    ...
};
Derived& asDerived() { return *static_cast<Derived*>(this); }
Derived const& asDerived() const {
    return *static_cast<Derived const*>(this);
}
reference operator*() const {
    return asDerived().dereference();
}
Derived& operator++() {
    asDerived().increment();
    return asDerived();
}
Derived operator++(int) {
    Derived result(asDerived());
    asDerived().increment();
    return result;
}
friend bool operator== (IteratorFacade const& lhs,
    IteratorFacade const& rhs) {
    return lhs.asDerived().equals(rhs.asDerived());
}

定义一个链表迭代器

// inherit/listnode.hpp
template<typename T>
class ListNode {
public:
    T value;
    ListNode<T>* next = nullptr;
    ~ListNode() { delete next; }
};

// inherit/listnodeiterator0.hpp

template<typename T>
class ListNodeIterator
: public IteratorFacade<ListNodeIterator<T>, T,
std::forward_iterator_tag>
{
    ListNode<T>* current = nullptr;
public:
    T& dereference() const {
        return current->value;
    }
    void increment() {
        current = current->next;
    }
    bool equals(ListNodeIterator const& other) const {
        return current == other.current;
    }
    ListNodeIterator(ListNode<T>* current = nullptr) :
    current(current) { }
};

隐藏接口

// inherit/iteratorfacadeaccessskel.hpp

// 友元该类以允许IteratorFacade访问核心的迭代器操作
// 即friend class IteratorFacadeAccess;
class IteratorFacadeAccess {
    // 只有IteratorFacade能使用这些定义
    template<typename Derived, typename Value,
        typename Category, typename Reference,
        typename Distance>
    friend class IteratorFacade;

    // 所有迭代器的要求
    template<typename Reference, typename Iterator>
    static Reference dereference(Iterator const& i) {
        return i.dereference();
    }
    ...

    // 双向迭代器的要求
    template<typename Iterator>
    static void decrement(Iterator& i) {
        return i.decrement();
    }

    // 随机访问迭代器的要求
    template<typename Iterator, typename Distance>
    static void advance(Iterator& i, Distance n) {
        return i.advance(n);
    }
    ...
};

迭代器适配器

// inherit/person.hpp
struct Person {
    std::string firstName;
    std::string lastName;
    friend std::ostream& operator<<(std::ostream& strm,
        Person const& p) {
        return strm << p.lastName << ", " << p.firstName;
    }
};
// inherit/projectioniteratorskel.hpp
template<typename Iterator, typename T>
class ProjectionIterator
: public IteratorFacade<
    ProjectionIterator<Iterator, T>,
    T,
    typename std::iterator_traits<Iterator>::iterator_category,
    T&,
    typename std::iterator_traits<Iterator>::difference_type>
{
    using Base = 
        typename std::iterator_traits<Iterator>::value_type;
    using Distance =
        typename std::iterator_traits<Iterator>::difference_type;

    Iterator iter;
    T Base::* member;

    friend class IteratorFacadeAccess
    ... // implement core iterator operations for IteratorFacade
public:
    ProjectionIterator(Iterator iter, T Base::* member)
    : iter(iter), member(member) { }
};

template<typename Iterator, typename Base, typename T>
auto project(Iterator iter, T Base::* member) {
    return ProjectionIterator<Iterator, T>(iter, member);
}
T& dereference() const {
    return (*iter).*member;
}
void increment() {
    ++iter;
}
bool equals(ProjectionIterator const& other) const {
    return iter == other.iter;
}
void decrement() {
    --iter;
}
// inherit/projectioniterator.cpp

#include <vector>
#include <algorithm>
#include <iterator>

int main()
{
    std::vector<Person> authors =
        { {"David", "Vandevoorde"},
        {"Nicolai", "Josuttis"},
        {"Douglas", "Gregor"} };
    std::copy(project(authors.begin(), &Person::firstName),
        project(authors.end(), &Person::firstName),
        std::ostream_iterator<std::string>(std::cout, "\n"));
}

// output
David
Nicolai
Douglas

Mixins

class Point {
public:
    double x, y;
    Point() : x(0.0), y(0.0) { }
    Point(double x, double y) : x(x), y(y) { }
};

class Polygon {
private:
    std::vector<Point> points;
public:
    ... // public operations
};
template<typename P>
class Polygon {
private:
    std::vector<P> points;
public:
    ... // public operations
};
class LabeledPoint : public Point
{
public:
    std::string label;
    LabeledPoint() : Point(), label("") { }
    LabeledPoint(double x, double y) : Point(x, y), label("") {}
};
template<typename... Mixins>
class Point : public Mixins...
{
public:
    double x, y;
    Point() : Mixins()..., x(0.0), y(0.0) { }
    Point(double x, double y) : Mixins()..., x(x), y(y) { }
};
class Label {
public:
    std::string label;
    Label() : label("") { }
};

using LabeledPoint = Point<Label>;
class Color {
public:
    unsigned char red = 0, green = 0, blue = 0;
};
using MyPoint = Point<Label, Color>;
template<typename... Mixins>
class Polygon
{
private:
    std::vector<Point<Mixins...>> points;
public:
    ... // public operations
};

Curious Mixins

template<template<typename>... Mixins>
class Point : public Mixins<Point>...
{
public:
    double x, y;
    Point() : Mixins<Point>()..., x(0.0), y(0.0) { }
    Point(double x, double y) : Mixins<Point>()..., x(x), y(y) { }
};

参数化虚拟性

#include <iostream>

class NotVirtual {
};

class Virtual {
public:
    virtual void foo() {
    }
};

template <typename... Mixins>>
class Base : private Mixins... {
public:
    // the virtuality of foo() depends on its declaration
    // (if any) in the base class Mixins...
    void foo() {
       std::cout << "Base::foo()" << '\n';
    }
};

template <typename... Mixins>
class Derived : public Base<Mixins...> {
public:
    void foo() {
        std::cout << "Derived::foo()" << '\n';
    }
};

int main()
{
    Base<NotVirtual>* p1 = new Derived<NotVirtual>;
    p1->foo();  // calls Base::foo()

    Base<Virtual>* p2 = new Derived<Virtual>;
    p2->foo();  // calls Derived::foo()
}

命名模板参数

template<typename Policy1 = DefaultPolicy1,
    typename Policy2 = DefaultPolicy2,
    typename Policy3 = DefaultPolicy3,
    typename Policy4 = DefaultPolicy4>
class BreadSlicer {
    ...
};
template <typename PolicySetter1 = DefaultPolicyArgs,
    typename PolicySetter2 = DefaultPolicyArgs,
    typename PolicySetter3 = DefaultPolicyArgs,
    typename PolicySetter4 = DefaultPolicyArgs>
class BreadSlicer {
    using Policies =  PolicySelector<PolicySetter1, PolicySetter2,
        PolicySetter3, PolicySetter4>;
    // use Policies::P1, Policies::P2, ... to refer to the various policies
    ...
};
// PolicySelector<A,B,C,D> creates A,B,C,D as base classes
// Discriminator<> allows having even the same base class more than once

template<typename Base, int D>
class Discriminator : public Base {
};

template <typename Setter1, typename Setter2,
    typename Setter3, typename Setter4>
class PolicySelector : public Discriminator<Setter1,1>,
    public Discriminator<Setter2,2>,
    public Discriminator<Setter3,3>,
    public Discriminator<Setter4,4> {
};
// name default policies as P1, P2, P3, P4
class DefaultPolicies {
public:
    using P1 = DefaultPolicy1;
    using P2 = DefaultPolicy2;
    using P3 = DefaultPolicy3;
    using P4 = DefaultPolicy4;
};
// class to define a use of the default policy values
// avoids ambiguities if we derive from DefaultPolicies more than once
class DefaultPolicyArgs : virtual public DefaultPolicies {
};
template <typename Policy>
class Policy1_is : virtual public DefaultPolicies {
public:
    using P1 = Policy; // overriding type alias
};

template <typename Policy>
class Policy2_is : virtual public DefaultPolicies {
public:
    using P2 = Policy; // overriding type alias
};

template <typename Policy>
class Policy3_is : virtual public DefaultPolicies {
public:
    using P3 = Policy; // overriding type alias
};

template <typename Policy>
class Policy4_is : virtual public DefaultPolicies {
public:
    using P4 = Policy; // overriding type alias
};
BreadSlicer<Policy3_is<CustomPolicy>> bc;
PolicySelector<Policy3_is<CustomPolicy>,
    DefaultPolicyArgs,
    DefaultPolicyArgs,
    DefaultPolicyArgs>
template<...>
class BreadSlicer {
    ...
public:
    void print () {
        Policies::P3::doPrint();
    }
    ...
};
#include <iostream>

// PolicySelector<A,B,C,D> creates A,B,C,D as base classes
// - Discriminator<> allows having even the same base class more than once

template <typename Base, int D>
class Discriminator : public Base {
};

template <typename Setter1, typename Setter2,
          typename Setter3, typename Setter4>
class PolicySelector : public Discriminator<Setter1,1>,
                       public Discriminator<Setter2,2>,
                       public Discriminator<Setter3,3>,
                       public Discriminator<Setter4,4> {
};


// default policies

class DefaultPolicy1 {};
class DefaultPolicy2 {};
class DefaultPolicy3 {
  public:
    static void doPrint() {
        std::cout << "DefaultPolicy3::doPrint()\n";
    }
};
class DefaultPolicy4 {};


// define default policies as P1, P2, P3, P4
class DefaultPolicies {
  public:
    using P1 = DefaultPolicy1;
    using P2 = DefaultPolicy2;
    using P3 = DefaultPolicy3;
    using P4 = DefaultPolicy4;
};


// class to define a usage of the default policy values
// - avoids ambiguities if we derive from DefaultPolicies more than once
class DefaultPolicyArgs : virtual public DefaultPolicies {
};


// class templates to override the default policy values

template <typename Policy>
class Policy1_is : virtual public DefaultPolicies {
  public:
    using P1 = Policy;  // overriding type alias
};

template <typename Policy>
class Policy2_is : virtual public DefaultPolicies {
  public:
    using P2 = Policy;  // overriding type alias
};

template <typename Policy>
class Policy3_is : virtual public DefaultPolicies {
  public:
    using P3 = Policy;  // overriding type alias
};

template <typename Policy>
class Policy4_is : virtual public DefaultPolicies {
  public:
    using P4 = Policy;  // overriding type alias
};


// create class template with four policies and default values

template <typename PolicySetter1 = DefaultPolicyArgs,
          typename PolicySetter2 = DefaultPolicyArgs,
          typename PolicySetter3 = DefaultPolicyArgs,
          typename PolicySetter4 = DefaultPolicyArgs>
class BreadSlicer {
    typedef PolicySelector<PolicySetter1, PolicySetter2,
                           PolicySetter3, PolicySetter4>
            Policies;
    // use Policies::P1, Policies::P2, //... to refer to the various policies.
  public:
    void print () {
        Policies::P3::doPrint();
    }
    //...
};


// define a custom policy
class CustomPolicy {
  public:
    static void doPrint() {
        std::cout << "CustomPolicy::doPrint()\n";
    }
};

int main()
{
    BreadSlicer<> bc1;
    bc1.print();

    BreadSlicer<Policy3_is<CustomPolicy>> bc2;
    bc2.print();
}
上一篇下一篇

猜你喜欢

热点阅读