C++模板编程 自定义创建元组(tuple)

一、各个模块

1、将数组转换为指针

// decay_array to pointer
template
auto decay_array(T(&array)[N])
{
	return array;
}

2、定义初始模板类型

1)元素类型为T

2)容器类型为T

3)是否为字符数组类型:否

4)数组大小:0

// primary class template
template
struct container_element_st
{
	using type = T;
	using element_type = T;
	static constexpr bool is_character_array = false;
	static constexpr size_t array_count = 0;
};

3、定义字符数组类型

1)元素类型为char

2)容器类型为std::string

3)是否为字符数组类型:是

4)数组大小:N

template
struct container_element_st	 // non reference
{
	using type = char;
	using element_type = std::string;
	static constexpr bool is_character_array = true;
	static constexpr size_t array_count = N;
};

4、定义字符指针类型

1)元素类型为char

2)容器类型为std::string

3)是否为字符数组类型:是

4)数组大小:0

template<>
struct container_element_st	 // non reference
{
	using type = char;
	using element_type = std::string;
	static constexpr bool is_character_array = true;
	static constexpr size_t array_count = 0;
};

5、定义非字符类型数组

1)元素类型为T

2)容器类型为std::vector

3)是否为字符数组类型:否

// array but not character array
template
struct container_element_st
{
	using type = T;
	using element_type = std::vector;
	static constexpr bool is_character_array = false;
};

6、定义初始化列表类型

1)元素类型为T

2)容器类型为std::vector

3)是否为字符数组类型:否

// from initializer_list to vector conversion
template
struct container_element_st>
{
	using type = T;
	using element_type = std::vector;
	static constexpr bool is_character_array = false;
};

7、定义各种类型

1)是否为字符数组类型

2)获取字符数组的大小

3)获取字符数组的类型,char or wchar_t

4)获取容器类型

// get whethere character array
template
constexpr auto is_character_array_v = container_element_st>::is_character_array;

// get array size
template
constexpr auto array_count_v = container_element_st< tft::remove_const_reference_t>::array_count;

// define element type
template
using element_flat_t = typename container_element_st< tft::remove_const_reference_t>::type;

// define container element type
template
using container_element_t = typename container_element_st< tft::remove_const_reference_t>::element_type;

8、创建自定义元组

创建元组的时候,元组的元素可以是元组,可以使vector,也可以是各种基础类型元素。

template
auto make_tuple(Type&& first, Types&&... args)
{
	using container_t = std::tuple, container_element_t...>;
	
	return container_t{ element_to_container(std::forward(first)),
		element_to_container(std::forward(args))... };
}

9、获取自定义元组中的元素

分别可以获取一层元组的元素、两层元组的元素、三层元组的元素。

template
decltype(auto) get(CntrType& cntr)
{
	return std::get(cntr);
}

template
decltype(auto) get(CntrType& cntr)
{
	if constexpr (sizeof...(Indices) > 0)
		return get(get(cntr));
	else
		return get(cntr);
}

template
decltype(auto) get(CntrType& cntr, IndexType index)
{
	if constexpr (sizeof...(Indices) > 0)
		return get(get(cntr))[index];
	else
		return get(cntr)[index];
}

二、整体代码

#include "tft_type_lib.h"
#include "tpf_type_util.h"

auto stream = tpf::stream();			// stream
auto nl = stream.get_console_out();	  // new line

// decay_array to pointer
template
auto decay_array(T(&array)[N])
{
	return array;
}

// primary class template
template
struct container_element_st
{
	using type = T;
	using element_type = T;
	static constexpr bool is_character_array = false;
	static constexpr size_t array_count = 0;
};

template
struct container_element_st	 // non reference
{
	using type = char;
	using element_type = std::string;
	static constexpr bool is_character_array = true;
	static constexpr size_t array_count = N;
};

template<>
struct container_element_st	 // non reference
{
	using type = char;
	using element_type = std::string;
	static constexpr bool is_character_array = true;
	static constexpr size_t array_count = 0;
};

template
struct container_element_st	 // non reference
{
	using type = wchar_t;
	using element_type = std::wstring;
	static constexpr bool is_character_array = true;
	static constexpr size_t array_count = N;
};

template<>
struct container_element_st	 // non reference
{
	using type = wchar_t;
	using element_type = std::wstring;
	static constexpr bool is_character_array = true;
	static constexpr size_t array_count = 0;
};

// array but not character array
template
struct container_element_st
{
	using type = T;
	using element_type = std::vector;
	static constexpr bool is_character_array = false;
};

template
struct container_element_st
{
	using type = T;
	using element_type = std::vector;
	static constexpr bool is_character_array = false;
};

// from initializer_list to vector conversion
template
struct container_element_st>
{
	using type = T;
	using element_type = std::vector;
	static constexpr bool is_character_array = false;
};

// get whethere character array
template
constexpr auto is_character_array_v = container_element_st>::is_character_array;

// get array size
template
constexpr auto array_count_v = container_element_st< tft::remove_const_reference_t>::array_count;

// define element type
template
using element_flat_t = typename container_element_st< tft::remove_const_reference_t>::type;

// define container element type
template
using container_element_t = typename container_element_st< tft::remove_const_reference_t>::element_type;

// create a vector
template
auto make_vector(Type&& first, Types&&... args)
{
	// determine whether type argument is an array
	if constexpr (std::is_array_v>)
	{
		// this is to allow only character array
		static_assert(is_character_array_v, "should be character array");

		using element_t = container_element_t;
		using container_t = std::vector;

		size_t size = array_count_v;
		const auto& last_character = first[size - 1];

		// last character is NULL character
		if (element_flat_t{} == last_character)
			return container_t{ decay_array(first),decay_array(args)... };
		else
		{
			return	container_t{ element_t{std::cbegin(first),std::cend(first)},
					element_t{std::cbegin(args),std::cend(args)}... };
		}
	}
	else
	{
		using element_t = tft::remove_const_reference_t;
		return std::vector{ std::forward(first), std::forward(args)... };
	}
}

// 创建一个容器
template< template class CntrType, typename Type, typename... Types>
auto make_container(Type&& first, Types&&... args)
{
	if constexpr (std::is_array_v>)
	{
		// this is to allow only character only
		static_assert(is_character_array_v, "should be character array");

		using element_t = container_element_t;
		using container_t = CntrType;

		size_t size = array_count_v;
		const auto& last_character = first[size - 1];

		// last character is NULL character
		if (element_flat_t{} == last_character)
			return container_t{ decay_array(first),decay_array(args)... };
		else
		{
			return	container_t{ element_t{std::cbegin(first),std::cend(first)},
					element_t{std::cbegin(args),std::cend(args)}... };
		}
	}
	else
	{
		using element_t = tft::remove_const_reference_t;
		return CntrType{ std::forward(first), std::forward(args)... };
	}
}

template
void print_type(T&& arg)
{
	stream << "Type of T:" << Tpf_GetTypeName(T)
		<< ", Type of arg: " << Tpf_GetTypeCategory(decay_array(arg)) << nl;
}

void simple_tip()
{
	int a = 1;
	std::vector v1{ 1,2,3,4,5 };
	auto v2 = make_vector(a, 2, 3, 4, 5, 6, 7, 8, 9, 10);
	stream << "v1 = " << v1 << nl;
	stream << "v2 = " << v2 << nl;

	auto v3 = make_vector("123", "tomas kim", "han", "saimei", "shuang");
	stream << "v3 = " << v3 << nl;
}

void simple_tip_advance()
{
	int a = 1;
	std::vector v1{ 1,2,3,4,5 };
	auto v2 = make_container(a, 2, 3, 4, 5, 6, 7, 8, 9, 10);
	stream << "v1 = " << v1 << nl;
	stream << "v2 = " << v2 << nl;

	auto v3 = make_container("123", "tomas kim", "han", "saimei", "shuang");
	stream << "v3 = " << v3 << nl;
}

/*
	we have to convert const char* to  std::string
	const wchar_t* to std::wstring
	convert array,int[] to std::vector
	std::initializer_list<> to std::vector<>
*/

template
auto element_to_container(Type&& arg)
{
	// array  such as char[N],int[N] ect.
	if constexpr (std::is_array_v>)
	{
		if constexpr (is_character_array_v)
		{
			// character array ,we convert 
			// const char* to std::string
			// const wchar_t* to std::wstring
			// char[N] to std::string
			// wchar_t[N] to std::wstring
			using element_t = container_element_t;
			size_t size = array_count_v;
			const auto& last_character = arg[size - 1];
			
			// element_flat_t returns either char or wchar_t
			// testing if zero terminated character
			if (element_flat_t{} == last_character)
				return element_t{ decay_array(arg) };// decay_array() convert char[] to char*
			else // not zero terminating character array
				return element_t{ std::cbegin(arg),std::cend(arg) };
		}
		else
		{
			// non character array
			using element_t = container_element_t;
			return element_t{ std::cbegin(arg),std::cend(arg) };
		}
	}
	else
	{
		// non array case
		using element_t = container_element_t;
		return element_t{ std::forward(arg) };
	}
}

// this belongs to non-deduced context
template
auto element_to_container(std::initializer_list& lst)
{
	// decltype(lst),decltype(),get variable type
	// using element_t = container_element_t>;
	using element_t = container_element_t;

	// conversion from std::initializer_list to std::vector
	return element_t{ lst };
}

// this belongs to non-deduced context
template
auto element_to_container(std::initializer_list&& lst)
{
	// decltype(lst),decltype(),get variable type
	// using element_t = container_element_t>;
	using element_t = container_element_t;

	// conversion from std::initializer_list to std::vector
	return element_t{ std::forward>(lst) };
}

template
auto make_tuple(Type&& first, Types&&... args)
{
	using container_t = std::tuple, container_element_t...>;
	
	return container_t{ element_to_container(std::forward(first)),
		element_to_container(std::forward(args))... };
}

template
decltype(auto) get(CntrType& cntr)
{
	return std::get(cntr);
}

template
decltype(auto) get(CntrType& cntr)
{
	if constexpr (sizeof...(Indices) > 0)
		return get(get(cntr));
	else
		return get(cntr);
}

template
decltype(auto) get(CntrType& cntr, IndexType index)
{
	if constexpr (sizeof...(Indices) > 0)
		return get(get(cntr))[index];
	else
		return get(cntr)[index];
}

void test_element_to_container()
{
	using literal_string_t = const char*;

	auto str1 = element_to_container("This is literal string");
	stream << "str1 = " << str1 << "\nType: "
		<< Tpf_GetTypeCategory(str1) << nl;

	int array[]{ 1,2,3,4,5 };
	auto vtr1 = element_to_container(array);
	stream << "vtr1 = " << vtr1 << "\nType: "
		<< Tpf_GetTypeCategory(vtr1) << nl;

	auto lst = element_to_container({ 3.1,5.0,6.0 });
	stream << "lst = " << lst << "\nType: "
		<< Tpf_GetTypeCategory(lst) << nl;

}

void test_make_tuple()
{
	const char* msg1 = "Literal string";
	const wchar_t* msg2 = L"wide character string";
	auto t1 = make_tuple(msg1,"han", "shuang", "shuang han", 20, "sia mie",msg2);
	stream << "t1 = " << t1 << /*"\nType: "
		<< Tpf_GetTypeCategory(t1) <<*/ nl;

	using t1_0_th_t = std::tuple_element_t<0, decltype(t1)>;
	stream << "t1-0-th element: " << std::get<0>(t1) << "\n Type: "
		<< Tpf_GetTypeName(t1_0_th_t) << nl;

	using t1_4_th_t = std::tuple_element_t<4, decltype(t1)>;
	stream << "t1-4-th element: " << std::get<4>(t1) << "\n Type: "
		<< Tpf_GetTypeName(t1_4_th_t) << nl;

	using t1_6_th_t = std::tuple_element_t<6, decltype(t1)>;
	stream << "t1-6-th element: " << std::get<6>(t1) << "\n Type: "
		<< Tpf_GetTypeName(t1_6_th_t) << nl;
}

void test_advanced_make_tuple()
{
	auto t1 = make_tuple(
		make_tuple(1, 3.14, "han"),
		make_tuple(make_vector(1, 2, 3, 4, 5), make_vector(3.0, 5.0, 6.1),
			make_tuple("han", "s shuang", 40.2f)),
		make_vector("james", "seveten"));

	stream << t1 << nl;
	stream << get<0>(t1) << nl;
	stream << get<1>(t1) << nl;

	stream << get<1, 0>(t1) << nl;
	stream << get<1, 1>(t1) << nl;
	stream << get<1, 2>(t1) << nl;

	stream << nl;

	//get<1, 0>(t1) is a vector
	for (const auto& e : get<1, 0>(t1))
		stream << e << " ";
	stream << nl;
}

int main()
{
	//test_element_to_container();
	//test_make_tuple();
	test_advanced_make_tuple();
	return 0;
}

你可能感兴趣的:(C++,C++模板编程,自定义创建元组)