《Beginning C++17》-学习笔记-Chapter 09-Functions Templates

// Using a function template
#include <iostream>
#include <string>
#include <vector>

template<typename T> T larger(T a, T b);    // Function template prototype

// a specialization of the template
template <>
int* larger<int*>(int* a, int* b)
{
	return *a > *b ? a : b;
}


int* larger(int* a, int* b); // Function overloading the larger template

//define a template that overloads the larger() template above

template <typename T>
T larger(const T data[], size_t count)
{
	T result{ data[0] };
	for (size_t i{ 1 }; i < count; ++i)
		if (data[i] > result) result = data[i];
	return result;
}

//define another template overload for vector
template <typename T>
T larger(const std::vector<T>& data)
{
	T result{ data[0] };
	for (auto& value : data)
		if (value > result) result = value;
	return result;
}
// overload the original template with another template specifically for pointer types
template<typename T>
T* larger(T* a, T* b)
{
	return *a > *b ? a : b;
}


int main()
{
	std::cout << "Larger of 1.5 and 2.5 is " << larger(1.5, 2.5) << std::endl;
	std::cout << "Larger of 3.5 and 4.5 is " << larger(3.5, 4.5) << std::endl;

	int big_int{ 17011983 }, small_int{ 10 };
	std::cout << "Larger of " << big_int << " and " << small_int << " is "
		<< larger(big_int, small_int) << std::endl;

	//using explicit instantiation of the template
	std::string a_string{ "A" }, z_string{ "Z" };
	std::cout << "Larger of \"" << a_string << "\" and \"" << z_string << "\" is "
		<< '"' << larger(a_string, z_string) << '"' << std::endl;

	/*You put the explicit type argument for the function template between angled brackets after the function
	name.This generates an instance with T as type double.*/
	std::cout << "Larger of " << small_int << " and 19.6 is "
		<< larger<double>(small_int, 19.6) << std::endl; // Outputs 19.6
	std::cout << "Larger of " << small_int << " and 19.6 is "
		<< larger<int>(small_int, 19.6) << std::endl; // Outputs 19
	std::cout << "Larger of " << small_int << " and 19.6 is "
		<< *(larger<int*>(&small_int, &big_int)) << std::endl; // Outputs 17011983
	std::cout << "Larger of " << small_int << " and 19.6 is "
		<< *larger(&small_int, &big_int) << std::endl; // Outputs 17011983

	int data_array[]{ 1,2,3,4,5 };
	std::cout << larger(data_array, std::size(data_array)) << std::endl;//output 5

	const std::vector<int> data_array1{ 1,2,3,4,5 };
	std::cout << larger(data_array1) << std::endl;//output 5

	std::cout << "Larger of " << small_int << " and 19.6 is "
		<< *larger(&small_int, &big_int) << std::endl; // Outputs 17011983

}

// Template for functions to return the larger of two values
template <typename T>
T larger(T a, T b)
{
	return a > b ? a : b;
}

int* larger(int* a, int* b)
{
	return *a > *b ? a : b;
}
#include <iostream>
#include <string>
#include <algorithm>//defines std::max() and std::min()

int main()
{
	int a{ 2 }, b{ 10 };
	std::string str_a{ "A" };
	std::string str_b{ "Z" };

	std::cout << "Larger of int a and b is " << std::max(a, b) << std::endl;
	std::cout << "Smaller of int a and b is " << std::min(a, b) << std::endl;

	std::cout << "Larger of string str_a and str_b is " << std::max(str_a, str_b) << std::endl;
	std::cout << "Smaller of string str_a and str_b is " << std::min(str_a, str_b) << std::endl;
}
// Using decltype() inside a function template
#include <iostream>
#include <vector>
#include <algorithm>	// for std::min()

// Template that computes a so-called "inner product" of two vectors.
// Both vectors are supposed to be equally long, 
// but the function will cope if they aren't.
template<typename T1, typename T2>
auto vector_product(const std::vector<T1>& data1, const std::vector<T2>& data2)
{
	// safeguard against vectors of different sizes
	const auto count = std::min(data1.size(), data2.size());

	decltype(data1[0] * data2[0]) sum{};
	for (size_t i{}; i < count; ++i)
		sum += data1[i] * data2[i];

	return sum;
}

int main()
{
	// Take the product of vectors with different types. Deduced return type: double
	std::vector<int> integers{ 1, 2, 3 };
	std::vector<double> doubles{ 1.1, 1.1, 1.1 };
	std::cout << vector_product(integers, doubles) << std::endl;

	// decltype() does not evaluate the expression, so this will work
	std::vector<bool> empty;
	std::cout << vector_product(empty, empty) << std::endl;
}
// Using decltype() inside a function template
#include <iostream>
/*Using a trailing decltype() syntax, the compiler will deduce the type from the return statements in the function
body.*/
template <typename T1, typename T2>
auto larger(T1 a, T2 b) -> decltype(a > b ? a : b)
{
	return a > b ? a : b;
}

int main()
{
	double num1{ 1.2 };
	int num2{ 3 };
	std::cout << larger(num1, num2) << std::endl;//output 3
}
// Using decltype() inside a function template
#include <iostream>
/*Using this syntax, the compiler will again deduce the type from the return statements in the function
body.*/
template <typename T1, typename T2>
decltype(auto) larger(T1 a, T2 b)
{
	return a > b ? a : b;
}

int main()
{
	double num1{ 1.2 };
	int num2{ 3 };
	std::cout << larger(num1, num2) << std::endl;//output 3
}
// Default Values for Template Parameters
#include <iostream>

template <typename TReturn = int, typename TArg1, typename TArg2>
TReturn larger(const TArg1 a, const TArg2 b)

{
	return a > b ? a : b;
}

int main()
{
	double num1{ 1.2 };
	double num2{ 3.5 };
	std::cout << larger(num1, num2) << std::endl;//output 3

}

// Default Values for Template Parameters
#include <iostream>

template <typename TArg, typename TReturn = TArg>
TReturn larger(const TArg a, const TArg b)

{
	return a > b ? a : b;
}

int main()
{
	double num1{ 1.2 };
	double num2{ 3.5 };
	std::cout << larger(num1, num2) << std::endl;//output 3.5

}
#include <iostream>
/*This template has a type parameter, T, and two nontype parameters, lower and upper, that are both
of type int.*/
template <int lower, int upper, typename T>
bool is_in_range(const T& value)
{
	return (value <= upper) && (value >= lower);
}

int main()
{
	int value{};
	std::cout << "Please enter a number." << std::endl;
	std::cin >> value;
	std::cout << value << (is_in_range<0, 500>(value) ? " is " : " isn't ") << "in the range from 0 to 500" << std::endl; // OK – checks 0 to 500

}
// Defining templates for functions that accept fixed-size arrays
#include <iostream>

template <typename T, size_t N>
T average(const T(&array)[N]);

int main()
{
	double doubles[2]{ 1.0, 2.0 };
	std::cout << average(doubles) << std::endl;

	double moreDoubles[]{ 1.0, 2.0, 3.0, 4.0 };
	std::cout << average(moreDoubles) << std::endl;

	/*Even though arrays and pointers are mostly equivalent,
	the compiler has no way of deducing the array size from a pointer.*/
	// double* pointer = doubles;
	// std::cout << average(pointer) << std::endl;      /* will not compile *

	//passing the brace-enclosed list as an argument.
	std::cout << average({ 1.0, 2.0, 3.0, 4.0 }) << std::endl;

	int ints[] = { 1, 2, 3, 4 };
	std::cout << average(ints) << std::endl;
}

template <typename T, size_t N>
T average(const T(&array)[N])
{
	T sum{};                            // Accumulate total in here
	for (size_t i{}; i < N; ++i)
		sum += array[i];                   // Sum array elements
	return sum / N;                      // Return average
}
// Defining a function template for adding numbers, 
// and an overload that works for pointer types.
// Extra: also make plus() work with string literals...
#include <iostream>
#include <string>
#include <string_view>

template <typename T>
T plus(const T a, const T b)
{
	return a + b;
}

// Overload with another template for pointer types
template <typename T>
T plus(const T* a, const T* b)
{
	return *a + *b;
}

std::string plus(const char* a, const char* b)
{
	return std::string{ a } +b;
}

int main()
{
	int n{ plus(3, 4) };
	std::cout << "plus(3, 4) returns " << n << std::endl;

	double d{ plus(3.2, 4.2) };
	std::cout << "plus(3.2, 4.2) returns " << d << std::endl;

	std::string s1{ "aaa" };
	std::string s2{ "bbb" };
	auto s3 = plus(s1, s2);
	std::cout << "With s1 as " << s1 << " and s2 as " << s2 << std::endl;
	std::cout << "plus(s1, s2) returns " << s3 << std::endl;

	// The extra part:
	std::string s{ plus("he", "llo") };
	std::cout << "plus(\"he\", \"llo\") returns " << s << std::endl;
}
// Your very own interpretation of std::size()
#include <iostream>
#include <array>
#include <vector>

// Look ma, no sizeof()!
template <typename T, size_t N>
inline size_t my_size(const T(&array)[N]) { return N; }

// Overload with two other templates for std::vector<> and array<> 
template <typename T>
inline size_t my_size(const std::vector<T>& vector) { return vector.size(); }

template <typename T, size_t N>
inline size_t my_size(const std::array<T, N>& array) { return N; }  // or array.size();

int main()
{
	int array[]{ 4, 8, 15, 16, 23, 42 };
	std::cout << "Size of numbers is " << my_size(array) << std::endl;//output 6

	// A string literal is also an array:
	std::cout << "Size of life lesson is "
		<< my_size("Always wear a smile. One size fits all.") << std::endl;//output 40

	std::vector<int> vector{ 4, 8, 15, 16, 23, 42 };
	std::cout << "Size of vector is " << my_size(vector) << std::endl;//output 6

	std::array<int, 6> array_object{ 4, 8, 15, 16, 23, 42 };
	std::cout << "Size of array_object is " << my_size(array_object) << std::endl;//output 6
}
	/*check for how many times one specific instance of a function template
	for any given argument type has been called.*/
	// The easiest way to verify this is using a static variable.
	// If indeed each function is only instantiated once, 
	// then all calls should share the same static variable...
	// You should see this being reflected in the program's output
	// as main() starts by calling the function for doubles twice.
#include <iostream>
#include <string>

template<typename T> T larger(T a, T b);    // Function template prototype

int main()
{
	std::cout << "Larger of 1.5 and 2.5 is " << larger(1.5, 2.5) << std::endl;
	std::cout << "Larger of 3.5 and 4.5 is " << larger(3.5, 4.5) << std::endl;

	int big_int{ 17011983 }, small_int{ 10 };
	std::cout << "Larger of " << big_int << " and " << small_int << " is "
		<< larger(big_int, small_int) << std::endl;

	std::string a_string{ "A" }, z_string{ "Z" };
	std::cout << "Larger of \"" << a_string << "\" and \"" << z_string << "\" is "
		<< '"' << larger(a_string, z_string) << '"' << std::endl;
}

// Template for functions to return the larger of two values
template <typename T>
T larger(T a, T b)
{

	static size_t counter{};
	std::cout << "This instantation has now been called " << ++counter << " time(s)\n";
	return a > b ? a : b;
}
// Exercise 9-6 A Quicksort funtion template

// The top level sort() template with one parameter calls the sort() template with three parameters
// The sort() function template uses the swap() function template
// The list() template outputs all elements in a vector.

#include <iostream>
#include <iomanip>
#include <vector>

// Swap two vector elements
template<typename T>
inline void swap(std::vector<T>& data, size_t first, size_t second)
{
	T temp{ data[first] };
	data[first] = data[second];
	data[second] = temp;
}

// Sort a range of vector elements
template<typename T>
void sort(std::vector<T>& data, size_t start, size_t end)
{
	// Start index must be less than end index for 2 or more elements
	if (!(start < end))
		return;

	// Choose middle value to partition set
	swap(data, start, (start + end) / 2);         // Swap middle value with start

	// Check data against chosen value
	size_t current{ start };                      // The index of the last element less than the chosen element (after partitioning)
	for (size_t i{ start + 1 }; i <= end; ++i)
	{
		if (data[i] < data[start])                  // Is value less than chosen element?
			swap(data, ++current, i);                 // Yes, so swap to the left
	}

	swap(data, start, current);                   // Swap the chosen value with last in

	if (current) sort(data, start, current - 1);  // Sort left subset if exists
	sort(data, current + 1, end);                 // Sort right subset if exists
}

// Sort all vector elements
template<typename T>
inline void sort(std::vector<T>& values)
{
	if (!values.empty())
		sort(values, 0, values.size() - 1);
}

// Output vector elements
template<typename T>
void list(const std::vector<T>& values, size_t width = 5)
{
	for (auto value : values)
		std::cout << std::setw(width) << value;
	std::cout << std::endl;
}

int main()
{
	std::vector<int> numbers{ -2, 4, -5, 6, 10, -40, 56, 4, 67, 45 };
	list(numbers);
	sort(numbers);
	std::cout << "\nSorted integers:\n";
	list(numbers);

	std::cout << "\nCharacters to be sorted:\n";
	std::vector<char> letters{ 'C', 'd', 'a', 'z', 't', 'S', 'p', 'm', 'D', 'f' };
	list(letters, 2);
	sort(letters);
	std::cout << "\nSorted characters:\n";
	list(letters, 2);

	std::cout << "\nFloating-point values to be sorted:\n";
	std::vector<double> values{ -2.5, 1.4, -2.55, 6.3, 10.1, -40.5, 56.0, 4.7, 67.3, 45.0 };
	list(values, 10);
	sort(values);
	std::cout << "\nSorted floaating-point values:\n";
	list(values, 10);
}

猜你喜欢

转载自blog.csdn.net/CodingIsFun/article/details/85011444