题目要求:假设有一个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;
}