借助deduce this改进奇异循环模板CRTP

奇异循环模板简介 crtp 是C++的常用惯用法,例如想实现运算符重载,派生类只需要实现+=操作,借助crtp,派生类的+操作也扩展的支持:

#include <iostream>
template <class D>
class B{
  public:
  D operator + (D rhs)
  {
    D tmp( static_cast<D&>(*this) );
    return tmp += rhs;

  }
};

class D:public B<D>
{
  int i_;
  public:
  D(int i):i_(i){}

  D& operator += (D const & r){
    i_+=r.i_;
    return *this;
  }
  int get()const{
    return i_;
  }
};

int main(){
  D d(1);
  D db(2);
  auto r = d+db;
  std::cout<<r.get()<<std::endl;
}

然而这种表示很不灵活,steve dewhurst给出了改进,使用策略:

#include <iostream>
template <class D>
template<template<class > class CRTP>
class DT:public CRTP<DT<CRTP>>
{
  int i_;
  public:
  DT(int i):i_(i){}

  DT& operator += (DT const & r){
    i_+=r.i_;
    return *this;
  }
  int get()const{
    return i_;
  }
};

int main(){
  DT<B> dt(1);
  DT<B> dtv(2);
  std::cout<<r.get()<<std::endl;
  std::cout<<rt.get()<<std::endl;
}

如果想支持多个策略,可使用variadic template

#include <iostream>
template <class D>
class B{
  public:
  D operator + (D rhs)
  {
    D tmp( static_cast<D&>(*this) );
    return tmp += rhs;
  }
};
template <class D>
class Mul{
  public:
  D operator * (D rhs)
  {
    D tmp( static_cast<D&>(*this) );
    return tmp *= rhs;
  }
};

template<template<class... > class... CRTP>
class DT:public CRTP<DT<CRTP...>>...
{
  int i_;
  public:
  DT(int i):i_(i){}

  DT& operator += (DT const & r){
    i_+=r.i_;
    return *this;
  }
  DT& operator *= (DT const & r){
    i_*=r.i_;
    return *this;
  }
  int get()const{
    return i_;
  }
};

int main(){
  DT<B,Mul> dt(1);
  DT<B,Mul> dtv(2);
  auto rt = dt+dtv;
  auto rtb = dt*dtv;
  std::cout<<rt.get()<<std::endl;
  std::cout<<rtb.get()<<std::endl;
}

借助C++23 的deduce this特性,可更加简化写法

#include <iostream>
class B{
  public:
  template<class T>
  T operator + (this  const T& self, const T& rhs)
  {
    T tmp(self );
    return tmp += rhs;
  }
};
class Mul{
  public:
  template<class T>
  T operator * (this  const T& self, const T& rhs)
  {
    T tmp(self );
    return tmp *= rhs;
  }
};
template< class... CRTP>
class DT:public CRTP...
{
  int i_;
  public:
  DT(int i):i_(i){}

  DT& operator += (DT const & r){
    i_+=r.i_;
    return *this;
  }
  DT& operator *= (DT const & r){
    i_*=r.i_;
    return *this;
  }
  int get()const{
    return i_;
  }
};

int main(){
  DT<B,Mul> dt(1);
  DT<B,Mul> dtv(2);
  auto rt = dt+dtv;
  dt*=dtv;
  auto rtb = dt*dtv;
  std::cout<<rtb.get()<<std::endl;
}

可以看到派生类的模板参数不是模板类型而只要是类类型便可支持策略。

Posted 2023-03-12