C++高级编程----模板的高级特性

该博客探讨了C++中如何使用模板实现Grid类,支持不同容器如vector和deque,并提供默认初始化值。同时,介绍了如何实现多维Grid,以及利用变长参数和元组进行函数调用和打印。通过模板参数特化,支持不同维度的Grid操作,例如Grid[x][y]=z。此外,还展示了如何利用模板和std::forward处理变长参数,以及通过递归模板实现元组的打印功能。
摘要由CSDN通过智能技术生成

题目要求:假设有一个Grid类,定义了一个网格的的大小(mWidth, mHeight),每个网格对于一个值(value),这个值可能是int,double,string等类型;存储整个网格的数据结构可以是vector,可以是deque,可以提供默认初始值;可以支持二维、三维拓展;对于其中的一些函数,希望支持变长参数控制,支持元组类型的打印控制;

分析:
1)支持Grid<int, vector>, Grid<int, deque>, Grid,容器模板类编程支持vector、deque和默认为vector,定义temple<typename T, typename Container = std::vector>,支持简化版Grid<int, vector>,定义template<typename T, template<typename E, typename Allocator = std::allocator> class Container = std::vector>;

2)支持Grid默认填充0,Grid<int, 10>默认填充10,支持Grid<classA, objA>定义 template<typename T, const T& DEFAULT>

3)支持多维数据Grid[x][y] = z,Grid[i][j][k] = r等,定义循环递归类NDGrid<typename T, size_t N-1>,定义基本条件(模板特例化):template class NDGrid<T, 1>;
4) 变长参数控制函数processValue(1, 2, 3.56, “test”, 1.1f),考虑非const引用和左值引用,设计template<typename T1, typename … Tn> + std::forward(args…)方法;

5)支持打印auto t1 = make_tuple(1, 2, 3.56, “test”, 1.1f); tuple_print(t1),打印元组,定义tuple_print_helper<n - 1, TupleType> tp(t)和tuple_print_helper<0, TupleType>类递归打印元组各个值

方法实现和测试
分析1:实现容器模板和默认容器填充、容器Allocator

// case 1:
/*
@File          :grid.h
@Description:  :template gird support vector/dequeue container
@Date          :2021/12/04 15:22:35
@Author        :    
@version       :1.0
*/
#pragma once
#include<vector>

// 1: basic version: 
// template<typename T, typename Container>
// 2:  template defalut, add default container for Grid class
// template<typename T, typename Container = std::vector<T>>
// 3: template template, support Grid<int, vector>, not only Grid<int, vector<int>>
template<typename T, template<typename E, typename Allocator = std::allocator<E>> class Container = std::vector>
class Grid{
   public:
       // constructor
       explicit Grid(size_t inWidth= kDefaultWidth, size_t inHeight = kDefaultHeight);
       
       // set value at (x, y)
       void setElement(size_t x, size_t y, const T& inElem);
       
       // get value at (x, y)
       T& getElement(size_t x, size_t y);
       const T& getElement(size_t x, size_t y) const;
       
       // get grid size with width and height
       size_t getWidth() const{return mWidth;}
       size_t getHeight() const{return mHeight;}

       // set default size
       static const size_t kDefaultWidth = 10;
       static const size_t kDefaultHeight = 10;

   private:
   void initalizeCellsContainer();
   // 2: std::vector<Container> mCells
   std::vector<Container<T>> mCells;
   size_t mWidth, mHeight;
};
// 2: template defalut
// template<typename T, typename Container>

// 3: template parmeter for template
template<typename T, template<typename E, typename Allocator = std::allocator<E>> class Container>
Grid<T, Container>::Grid(size_t inWidth, size_t inHeight):mWidth(inWidth), mHeight(inHeight){
   initalizeCellsContainer();
}

template<typename T, template<typename E, typename Allocator = std::allocator<E>> class Container>
void Grid<T, Container>::setElement(size_t x, size_t y, const T& inElem){
    /*
    @description  : set element at (x, y) with value inElem 
    @param  : location (x, y)
    @Returns  : None 
    */
    mCells[x][y] = inElem;
}

template<typename T, template<typename E, typename Allocator = std::allocator<E>> class Container>
T& Grid<T, Container>::getElement(size_t x, size_t y){
   /*
   @description  : get element at (x, y)
   @param  : location (x, y)
   @Returns  : value at (x, y)
   */
   return mCells[x][y];
}

template<typename T, template<typename E, typename Allocator = std::allocator<E>> class Container>
const T& Grid<T, Container>::getElement(size_t x, size_t y) const{
   /*
   @description  : get const version element at (x, y) 
   @param  : location (x, y)
   @Returns  : const value at (x, y)
   */
   return mCells[x][y];
}

template<typename T, template<typename E, typename Allocator = std::allocator<E>> class Container>
void Grid<T, Container>::initalizeCellsContainer(){
   /*
   @description  : initalize cells container helper to resize container 
   @param  : None
   @Returns  : None
   */
   mCells.resize(mWidth);
   for(auto& col : mCells){
       col.resize(mHeight);
   }
}

// main /

#include<iostream>
#include<vector>
#include<deque>

#include"gridContainer.h"

using namespace std;

int main(){
   // ----------------- test case 1 --------------------------//
   // // Grid<T, Constainer>
   // Grid<int, vector<int>> myVectorGrid;
   // Grid<int, deque<int>> myDequeGrid;
   
   // myVectorGrid.setElement(1, 2, 3);
   // cout << myVectorGrid.getElement(1, 2) << endl;

   // myDequeGrid.setElement(0, 0, 3);
   // cout << myDequeGrid.getElement(0, 0) << endl;
   // Grid<int, vector<int>> myVectorGrid2(myVectorGrid);
   // cout << myVectorGrid2.getElement(1,2);

   //error type: Grid<int, int> since the second template typename does not have the method resize() in initalizeCellsContainer()
   
   // ----------------- test case 2 --------------------------//
   Grid<int> myVectorDefault;  //Grid<int, vector<int>> 

   // ----------------- test case 3 --------------------------//
   Grid<int, vector> myVectorGrid;
   myVectorGrid.setElement(1, 2, 3);
   cout << myVectorGrid.getElement(1, 2) << endl;

   return 0;
}

分析2:实现默认值填充

#pragma once
#include<vector>

// non-typename only support: int, enum, pointer, reference
// template<typename T, const T DEFAULT = T()>
// reference template for other class
template<typename T, const T& DEFAULT>
class Grid{
    public:
        explicit Grid(size_t inWidth = kDefaultWidht, size_t inHeight = kDefaultHeight);

        // setter
        void setElement(size_t x, size_t y, const T& inElem);

        // getter
        T& getElement(size_t x, size_t y);
        const T& getElement(size_t x, size_t y) const;

        size_t getWidth() const {return mWidth;}
        size_t getHeight() const {return mHeight;}

        static const size_t kDefaultWidht = 10;
        static const size_t kDefaultHeight = 10;
    private:
        size_t mWidth;
        size_t mHeight;
        std::vector<std::vector<T>> mCells;
        void initalizeCellsContainer();
};

template<typename T, const T& DEFAULT>
Grid<T, DEFAULT>::Grid(size_t inWidth, size_t inHeight):mWidth(inWidth), mHeight(inHeight){
    initalizeCellsContainer();
}

template<typename T, const T& DEFAULT>
void Grid<T, DEFAULT>::setElement(size_t x, size_t y, const T& inElem){
    mCells[x][y] = inElem;
}

template<typename T, const T& DEFAULT>
T& Grid<T, DEFAULT>::getElement(size_t x, size_t y){
    return mCells[x][y];
}

template<typename T, const T& DEFAULT>
const T& Grid<T, DEFAULT>::getElement(size_t x, size_t y) const{
    return mCells[x][y];
}

template<typename T, const T& DEFAULT>
void Grid<T, DEFAULT>::initalizeCellsContainer(){
    mCells.resize(mWidth);
    for(auto& col:mCells){
        col.resize(mHeight);
        for(auto& elem:col){
            elem = DEFAULT;
        }
    }
}
/main/
#include<iostream>
#include<vector>
#include"girdElement.h"
#include"SpreadsheetCell.h"

using namespace std;

namespace{
    const int defaultInt = 11;
    SpreadsheetCell defaultCell(1.2);
}

// the second reference template must be const express, static inner or outter complete object
// so add namespace for const default for save

int main(){
    // --------------- test default -----------------------//
    // Grid<int> myDefaultGrid;
    // Grid<int, 10> myDefaultGrid2;
    // cout << myDefaultGrid.getElement(0, 0) << endl;
    // cout << myDefaultGrid2.getElement(0, 0) << endl;
    // error support: Grid(class, obj)

    // ----------- test reference template ----------------//
    Grid<int, defaultInt> myIntGrid;
    cout << myIntGrid.getElement(0, 0) << endl;
    Grid<SpreadsheetCell, defaultCell> mySpreadsheet;
    
    return 0;
}

分析3:多维Grid实现

#pragma once

#include<vector>

template<typename T, size_t N>
class NDGrid{
    public:
        // constructor
        explicit NDGrid(size_t inSize = kDefaultSize) {resize(inSize);};
        
        // operator
        NDGrid<T, N-1>& operator[](size_t x) {return mElems[x];};
        const NDGrid<T, N-1>& operator[](size_t x) const {return mElems[x];};

        void resize(size_t newSize) {mElems.resize(newSize);};
        size_t getSize() const {return mElems.size();};
        static const size_t kDefaultSize = 10;
    private:
        std::vector<NDGrid<T, N-1>> mElems;
};

template<typename T>
class NDGrid<T, 1>{
    public:
        explicit NDGrid(size_t inSize = kDefaultSize) {resize(inSize);};
        
        // operator
        T& operator[](size_t x) {return mElems[x];};
        const T& operator[](size_t x) const {return mElems[x];};

        void resize(size_t newSize) {mElems.resize(newSize);};
        size_t getSize() const {return mElems.size();};
        static const size_t kDefaultSize = 10;
    private:
        std::vector<T> mElems;
};

 main /
#include<iostream>
#include<vector>
#include"nDGrid.h"

using namespace std;

int main(){

    NDGrid<int, 3> threeDim(3);
    threeDim[0][0][0] = 1;
    return 0;
}

分析4:变长参数控制与解析

#include<iostream>
#include<string>

using namespace std;

void handleValue(int value){
    cout << "Interger: " << value << endl;
}

void handleValue(double value){
    cout << "Double: " << value << endl;
}

void handleValue(const string& value){
    cout << "String: " << value << endl;
}

template<typename T>
void processValue(T arg){
    handleValue(arg);
}

template<typename T1, typename ... Tn>
void processValue(T1 arg1, Tn ... argn){
    handleValue(arg1);
    processValue(argn...);
}

// non-const reference with std::forward() to imporve performence
template<typename T>
void processValueII(T&& arg){
    handleValue(std::forward<T>(arg));
}

template<typename T1, typename ... Tn>
void processValueII(T1 arg1, Tn ... argn){
    handleValue(arg1);
    processValueII(std::forward<Tn>(argn)...);
}
int main(){
    processValue(1, 2, 3.56, "test", 1.1f);
	cout << endl;
	processValueII(1, 2, 3.56, "test", 1.1f);
    return 0;
}

分析5:元组值输出 (元编程:在编译时完成计算,而不是运行时完成。由于元组是在编译时完成,因此可以通过模板类实现编译时遍历操作)

#include <iostream>
#include <string>
#include <tuple> 

using namespace std;

template<int n, typename TupleType>
class tuple_print_helper
{
public:
	tuple_print_helper(const TupleType& t) {
		tuple_print_helper<n - 1, TupleType> tp(t);
		cout << get<n - 1>(t) << endl;
	}
};

template<typename TupleType>
class tuple_print_helper<0, TupleType>
{
public:
	tuple_print_helper(const TupleType&) { }
};

template<typename T>
void tuple_print(const T& t)
{
	tuple_print_helper<tuple_size<T>::value, T> tph(t);
}

int main()
{
	auto t1 = make_tuple(1, 2, 3.56, "test", 1.1f);
	tuple_print(t1);

	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值