// 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);
}