c++11-模板元实战2

前言

黑魔法,应用场景 :
1.实现宿生语言
2.实现一些常规手段做不到的东西,比如 c++11::share_prt::enable_share_from_this
3.作为实现各种库的基本组件 :Stl,Boost,标准库都大量运用了模板元技术

很多人比较排斥这个东西...个人觉得实用就行,工具终究是为人服务的
just enjoy it 😃

推荐的资料

《C++ Templates》
《C++模板元编程》
C++11模板元入门 https://www.cnblogs.com/qicosmos/p/4480460.html
C++高质量社区 http://purecpp.org/

Part 2.1 CRTP

比较奇异的一种技术,我是从std::share_ptr::enable_share_from_this了解到的

1.通过继承基类(CRTP)来扩展派生类的接口

常规的继承时通过子类来扩展基类的功能
而CRTP反过来了...非常奇妙
实现一个可以被继承的单例模式

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
template<typename T>
struct signle
  {
  	public :
  		static T& get_signle()
  		  {
  		  	static T ret;
  		  	return ret;
			}
  	protected :
  		signle()
  		  {}
		signle(signle const& rhs) = delete;
  };
struct son : signle<son>
  {
  	friend class signle<son>;
  	protected :
  		son()
  		  {
  		  	cout << "son" << endl;
			}
  };
int main()
  {
  	auto &ret = son::get_signle();
  	cout << &ret << "\n";
	return 0;
  }

这样就没了,可以看到,能很方便的通过继承集成功能

2.实现一个调用链

这个文章的第三个例子,很清晰了
就是要求子类和父类都以父类的引用返回,实现调用链
https://zhuanlan.zhihu.com/p/137879448

3.实现静态多态

CRTP静多态的基本模式,cast是关键点,因为是安全的向下转型,static_cast就行了,没必要dynamic_cast

template<typename T>
struct crtp
  {
  	T& cast()
  	  {
  	  	return static_cast<T&>(*this); // safe
		} 
	void doit()
	  {
	  	cast().doit();
	  }
  }; 

有两种实现方式,一种是不采用CRTP的普通模板静多态,区别见下面这个问题 + 第一个回答
https://www.zhihu.com/question/332147621

和普通静多态相比,CRTP的特点

1.可以有默认行为,普通的静态多态要求每个子类必须写函数
2.可以很好的实现-设计模式-模板方法模式-即把一些公共操作提取到基类-避开继承导致的运行时消耗
3.采用多态的地方,都可以采用CRTP的方法,利用模板自己实现虚函数...编码略微复杂...但是可以提高运行速度...也就是去除运行时处理虚表的消耗...不太安全

非以上情况的静多态,采用普通静态多态更合适

c++ 实现原型模式:clone()
等效于手工实现了虚表

#include <bits/stdc++.h>
using namespace std;
using ll = long long int;

struct AbstractShape
  {
    enum class_type {Square,Circle} name;
};

template <typename Derived>
struct Shape : public AbstractShape    // Shape中填写默认操作 
  {
  	Derived& cast()
  	  {
  	  	return static_cast<Derived&>(*this);
		}
		
    void doit_face()
      {
      	cast().doit();
	  }
	void doit()
      {
      	cout << "shape" << endl;
	  }
	  
	AbstractShape* clone_face()
      {
      	return cast().clone();
	  }
	AbstractShape* clone()
	  {
	  	cout << "debug+ clone+ " << typeid(Derived).name() << endl;
        return static_cast<AbstractShape*>(new Derived(cast()));
      }
      
};

struct Square : public Shape<Square>
  {
  	Square()
  	  {
  	  	name = AbstractShape::Square;
		}
	void doit()
	  {
	  	cout << "Square doit" << endl;
	  }
  };

struct Circle : public Shape<Circle>
  {
  	Circle()
  	  {
  	  	name = AbstractShape::Circle;
		}
	AbstractShape* clone()
	  {
	  	cout << "debug+ clone+ null" << endl;
        return nullptr;
      }
  };
#define call_2(rhs,func_name)                            \
do{                                                      \
  	switch(rhs -> name)                                  \
  	  {                                                  \
  	  	case AbstractShape::Square :                     \
  	  	  {                                              \
  	  	  	static_cast<Shape<Square>*>(rhs) -> func_name();  \
  	  	  	break;                                       \
			}                                            \
		case AbstractShape::Circle :                     \
  	  	  {                                              \
  	  	  	static_cast<Shape<Circle>*>(rhs) -> func_name();  \
  	  	  	break;                                       \
			}                                            \
		  }                                              \
	}while(0)                                            

#define call_3(rhs,func_name,__result)                   \
do{                                                      \
  	switch(rhs -> name)                                  \
  	  {                                                  \
  	  	case AbstractShape::Square :                     \
  	  	  {                                              \
  	  	  	__result = static_cast<Shape<Square>*>(rhs) -> func_name();  \
  	  	  	break;                                       \
			}                                            \
		case AbstractShape::Circle :                     \
  	  	  {                                              \
  	  	  	__result = static_cast<Shape<Circle>*>(rhs) -> func_name();  \
  	  	  	break;                                       \
			}                                            \
		  }                                              \
	}while(0)        

 
#define VARGS_(_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,N,...) N 
#define VARGS(...) VARGS_(__VA_ARGS__,10,9,8,7,6,5,4,3,2,1,0)
#define CONCAT_(a,b) a##b
#define CONCAT(a,b) CONCAT_(a,b)
#define call(...) CONCAT(call_,VARGS(__VA_ARGS__))(__VA_ARGS__)

                                    
void f(AbstractShape * rhs)
  {
  	cout << "-----------------------" << endl;
  	
  	call(rhs,doit_face);
  	
  	AbstractShape* p;call(rhs,clone_face,p);
  	
  	if (p != NULL)
  	  call(p,doit_face);
  	  
  	cout << "-----------------------" << endl << endl;
	   
  }
int main()
  {
  	vector<AbstractShape*> v;
  	v.emplace_back(new Square);
  	v.emplace_back(new Circle);
  	v.emplace_back(new Square);
  	for (auto it : v)
  	  f(it);
  	return 0;
  }
posted @ 2021-06-07 19:16  XDU18清欢  阅读(38)  评论(0)    收藏  举报