您的位置:首页 > 编程语言 > C语言/C++

[C++模板]Loki中的Length和TypeAt使用C++11特性改进

2017-01-07 12:01 525 查看
C++模板变参实现Loki中的Length和TypeAt
一,原Loki中的Length和TypeAt模拟实现如下
1,模板文件
/**********************************
*
* Author : szyu
*
* Date : 2017.1.7
*
**************************************/

#ifndef __SZYU_LOKI__
#define __SZYU_LOKI__

#include <iostream>
#include <vector>

template <typename T, typename U>
class TypeList
{
public:
typedef T Head;
typedef U Tail;
};

class NullType;

#define TYPELIST_1(type1)               TypeList<type1, NullType>
#define TYPELIST_2(type1, type2)        TypeList<type1, TYPELIST_1(type2)>
#define TYPELIST_3(type1, type2, type3) TypeList<type1, TYPELIST_2(type2, type3)>

/*******************************************
*
* Loki Length
*
**********************************************/
template <typename T> class Length;

template <typename T, typename U>
class Length<TypeList<T, U> >
{
public:
enum { value = 1 + Length<U>::value };
};

template <>
class Length<NullType>
{
public:
enum { value = 0 };
};

/*******************************************
*
* Loki TypeAt
*
**********************************************/
template <typename T, unsigned int index> class TypeAt;

template <typename T, typename U, unsigned int index>
class TypeAt<TypeList<T, U>, index>
{
public:
typedef typename TypeAt<U, index - 1>::Result Result;
};

template <typename T, typename U>
class TypeAt<TypeList<T, U>, 0>
{
public:
typedef T Result;
};

#endif
2,测试用例
/**********************************
*
* Author : szyu
*
* Date : 2017.1.7
*
**************************************/

#include "loki.h"

void
test1()
{
std::cout << "Length<TYPELIST_1(int)>..." << Length<TYPELIST_1(int)>::value << std::endl;
std::cout << "Length<TYPELIST_2(int, int)>..." << Length<TYPELIST_2(int, int)>::value << std::endl;
std::cout << "Length<TYPELIST_3(int, int, int)>..." << Length<TYPELIST_3(int, int, int)>::value << std::endl;

std::cout << "************************************" << std::endl;
std::vector<int> IntVector;

std::cout << typeid(TypeAt<TYPELIST_3( double, std::string, std::vector<int>), 0>::Result).name() << std::endl;
std::cout << typeid(TypeAt<TYPELIST_3( double, std::string, std::vector<int>), 1>::Result).name() << std::endl;
std::cout << typeid(TypeAt<TYPELIST_3( double, std::string, std::vector<int>), 2>::Result).name() << std::endl;

TypeAt<TYPELIST_3( double, std::string, std::vector<int>), 0>::Result var1;
var1 = 10.10;

TypeAt<TYPELIST_3( double, std::string, std::vector<int>), 1>::Result var2;
var2 = "abc";

TypeAt<TYPELIST_3( double, std::string, std::vector<int>), 2>::Result var3;
var3 = IntVector;
}

int
main( int argc, char *argv[] )
{
test1();

return 0;
}
3,执行结果如下:




二,使用C++11模板变参特性改进Length和TypeAt
在不使用模板变参会出现繁杂的TypeList嵌套问题,虽然使用宏定义能增加代码可读性,但是也因此需要定义大量的宏来支持。当出现几百个参数(极端)情况下,那需要定义几百个宏。显然比较麻烦。C++11提供了模板的变参的支持,故变参实现Length和TypeAt如下:
1,头文件
/**********************************
*
* Author : szyu
*
* Date : 2017.1.6
*
***********************************/

#ifndef __SZYU_LOKI__
#define __SZYU_LOKI__

#include <iostream>
#include <vector>

/***********************************
*
* Loki length
*
***************************************/
template <typename T, typename... Args>
class Length
{
public:
enum { value = 1 + Length<Args...>::value };
};

template <typename T>
class Length<T>
{
public:
enum { value = 1 };
};

/***********************************
*
* Loki TypeAt
*
***************************************/
template <unsigned int index, typename T, typename... Args>
class TypeAt
{
public:
typedef typename TypeAt<index - 1, Args...>::Result Result;
};

template <typename T, typename... Args>
class TypeAt<1, T, Args...>
{
public:
typedef T Result;
};

#endif
2,测试用例
/**********************************
*
* Author : szyu
*
* Date : 2017.1.6
*
***********************************/

#include "TypeList.h"

void
test1()
{
std::cout << "Length<int>..." << Length<int>::value << std::endl;
std::cout << "Length<int, int>..." << Length<int, int>::value << std::endl;
std::cout << "Length<int, int, char>..." << Length<int, int, char>::value << std::endl;

std::cout << "********************************" << std::endl;
std::vector<int> IntVector;

std::cout << typeid(TypeAt<1, int, std::string, std::vector<int> >::Result).name() << std::endl;
std::cout << typeid(TypeAt<2, int, std::string, std::vector<int> >::Result).name() << std::endl;
std::cout << typeid(TypeAt<3, int, std::string, std::vector<int> >::Result).name() << std::endl;

TypeAt<1, int, std::string, std::vector<int> >::Result var1;
var1 = 10;

TypeAt<2, int, std::string, std::vector<int> >::Result var2;
var2 = "ssss";

TypeAt<3, int, std::string, std::vector<int> >::Result var3;
var3 = IntVector;
}

int
main( int argc, char *argv[] )
{
test1();

return 0;
}
3,执行结果




TypeAt的实现中,由于变参要位于最后一个参数,故把位置参数移到了模板第一个参数。

住:
Loki中Length和TypeAt的具体说明参见《c++设计新思维》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++