cpp
exercises
exercises.cpp⚙️cpp
/**
* Advanced Templates - Exercises
* Compile: g++ -std=c++17 -Wall exercises.cpp -o exercises
*/
#include <iostream>
#include <string>
#include <type_traits>
using namespace std;
// ============================================================
// Exercise 1: Variadic Print ⭐⭐
// ============================================================
// TODO: Create printLine(args...) that prints all arguments
// separated by " | " and ending with newline
void exercise1() {
// printLine(1, 2.5, "hello");
// Output: 1 | 2.5 | hello
cout << "(Implement variadic printLine)" << endl;
}
// ============================================================
// Exercise 2: Fold Sum/Product ⭐⭐
// ============================================================
// TODO: Create using fold expressions:
// - sumAll(args...) - returns sum
// - productAll(args...) - returns product
// - minAll(args...) - returns minimum
void exercise2() {
// cout << sumAll(1,2,3,4,5) << endl; // 15
// cout << productAll(1,2,3,4) << endl; // 24
// cout << minAll(5,2,8,1,9) << endl; // 1
cout << "(Implement fold expressions)" << endl;
}
// ============================================================
// Exercise 3: Type Checker ⭐⭐
// ============================================================
// TODO: Create getTypeInfo<T>() that returns string:
// "integral" for int, long, etc.
// "floating" for float, double
// "pointer" for pointer types
// "other" for everything else
// Use if constexpr
void exercise3() {
// cout << getTypeInfo<int>() << endl; // "integral"
// cout << getTypeInfo<double>() << endl; // "floating"
// cout << getTypeInfo<int*>() << endl; // "pointer"
cout << "(Implement type info with if constexpr)" << endl;
}
// ============================================================
// Exercise 4: Safe Divide ⭐⭐⭐
// ============================================================
// TODO: Create safeDivide(a, b) that:
// - Works with arithmetic types only (use SFINAE or if constexpr)
// - Returns a/b for integers (integer division)
// - Returns a/b for floating point
// - Returns 0 if b is 0
void exercise4() {
// cout << safeDivide(10, 3) << endl; // 3
// cout << safeDivide(10.0, 3.0) << endl; // 3.333...
// cout << safeDivide(5, 0) << endl; // 0
cout << "(Implement SFINAE safeDivide)" << endl;
}
// ============================================================
// Exercise 5: Compile-Time Power ⭐⭐⭐
// ============================================================
// TODO: Create template struct Power<Base, Exp>
// with static constexpr value member
// Power<2, 10>::value should be 1024
void exercise5() {
// cout << Power<2, 10>::value << endl; // 1024
// cout << Power<3, 4>::value << endl; // 81
cout << "(Implement compile-time Power)" << endl;
}
// ============================================================
// Exercise 6: Count Types ⭐⭐⭐
// ============================================================
// TODO: Create CountType<T, Types...> that counts
// how many times T appears in Types...
// CountType<int, int, double, int, char>::value = 2
void exercise6() {
// cout << CountType<int, int, double, int, char>::value << endl; // 2
// cout << CountType<char, int, double>::value << endl; // 0
cout << "(Implement CountType)" << endl;
}
// ============================================================
// Exercise 7: Invoke All ⭐⭐⭐
// ============================================================
// TODO: Create invokeAll(funcs..., arg) that calls
// each function with the same argument
void exercise7() {
// auto f1 = [](int x) { cout << x * 2 << " "; };
// auto f2 = [](int x) { cout << x + 1 << " "; };
// invokeAll(5, f1, f2); // prints: 10 6
cout << "(Implement invokeAll with variadic)" << endl;
}
// ============================================================
// Exercise 8: Make Array ⭐⭐⭐
// ============================================================
// TODO: Create makeArray(args...) that returns
// array<CommonType, sizeof...(args)>
// All args must be same or convertible type
void exercise8() {
// auto arr = makeArray(1, 2, 3, 4, 5);
// for (auto x : arr) cout << x << " ";
cout << "(Implement makeArray)" << endl;
}
// ============================================================
// MAIN
// ============================================================
int main() {
cout << "=== Advanced Templates Exercises ===" << endl;
cout << "\nEx1: Variadic Print" << endl;
exercise1();
cout << "\nEx2: Fold Operations" << endl;
exercise2();
cout << "\nEx3: Type Checker" << endl;
exercise3();
cout << "\nEx4: Safe Divide" << endl;
exercise4();
cout << "\nEx5: Compile-Time Power" << endl;
exercise5();
cout << "\nEx6: Count Types" << endl;
exercise6();
cout << "\nEx7: Invoke All" << endl;
exercise7();
cout << "\nEx8: Make Array" << endl;
exercise8();
return 0;
}
// ============================================================
// ANSWERS
// ============================================================
/*
Ex1:
void printLine() { cout << endl; }
template<typename T>
void printLine(T val) { cout << val << endl; }
template<typename T, typename... Args>
void printLine(T first, Args... rest) {
cout << first << " | ";
printLine(rest...);
}
Ex2:
template<typename... Args>
auto sumAll(Args... args) { return (... + args); }
template<typename... Args>
auto productAll(Args... args) { return (... * args); }
template<typename T, typename... Args>
auto minAll(T first, Args... rest) {
if constexpr (sizeof...(rest) == 0) return first;
else { auto m = minAll(rest...); return first < m ? first : m; }
}
Ex3:
template<typename T>
string getTypeInfo() {
if constexpr (is_integral_v<T>) return "integral";
else if constexpr (is_floating_point_v<T>) return "floating";
else if constexpr (is_pointer_v<T>) return "pointer";
else return "other";
}
Ex4:
template<typename T>
auto safeDivide(T a, T b) {
static_assert(is_arithmetic_v<T>);
if (b == 0) return T{0};
return a / b;
}
Ex5:
template<unsigned Base, unsigned Exp>
struct Power {
static constexpr unsigned value = Base * Power<Base, Exp-1>::value;
};
template<unsigned Base>
struct Power<Base, 0> {
static constexpr unsigned value = 1;
};
Ex6:
template<typename T, typename... Types>
struct CountType;
template<typename T>
struct CountType<T> { static constexpr int value = 0; };
template<typename T, typename First, typename... Rest>
struct CountType<T, First, Rest...> {
static constexpr int value =
(is_same_v<T, First> ? 1 : 0) + CountType<T, Rest...>::value;
};
Ex7:
template<typename Arg, typename... Funcs>
void invokeAll(Arg arg, Funcs... funcs) {
(funcs(arg), ...);
}
Ex8:
template<typename... Args>
auto makeArray(Args... args) {
using CT = common_type_t<Args...>;
return array<CT, sizeof...(args)>{static_cast<CT>(args)...};
}
*/