//Key goals:
// Work with any container type (not just std::vector)
// Work with any element type
// Accept any predicate (lambda, function pointer, functor)
// Avoid undefined behavior and handle edge cases gracefully
// Keep the code clean and modular
#include <vector>
#include <list>
#include <string>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <type_traits>
// ------------------------------------------------------------
// Helper: conditionally call reserve() if the container supports it
// ------------------------------------------------------------
template <typename Container>
auto try_reserve(Container& c, std::size_t n)
-> decltype(c.reserve(n), void())
{
c.reserve(n); // Only participates in overload resolution if reserve exists
}
inline void try_reserve(...)
{
// Fallback: do nothing if reserve() is not available
}
// ------------------------------------------------------------
// Generic filter function
// - Works with any container supporting begin/end and push_back
// - Accepts any unary predicate
// - Returns a new container of the same type
// ------------------------------------------------------------
template <typename Container, typename Predicate>
Container filter(const Container& input, Predicate pred)
{
Container output;
// Reserve capacity when possible (e.g., for std::vector)
try_reserve(output, input.size());
std::copy_if(input.begin(), input.end(),
std::back_inserter(output),
pred);
return output;
}
// ------------------------------------------------------------
// Helper to print any container
// ------------------------------------------------------------
template <typename Container>
void print(const Container& c, const std::string& label)
{
std::cout << label << ": ";
for (const auto& elem : c)
std::cout << elem << " ";
std::cout << "\n";
}
int main()
{
// -------------------------
// Test Case 1: Even numbers
// -------------------------
std::vector<int> nums = {1, 2, 3, 4, 5, 6};
auto evens = filter(nums, [](int x) { return x % 2 == 0; });
print(nums, "Original nums");
print(evens, "Filtered evens");
std::cout << "\n";
// -------------------------
// Test Case 2: Strings with length > 3
// -------------------------
std::vector<std::string> words = {"the", "world", "hi", "universe"};
auto longWords = filter(words, [](const std::string& s) {
return s.size() > 3;
});
print(words, "Original words");
print(longWords, "Filtered long words");
std::cout << "\n";
// -------------------------
// Test Case 3: Filtering a std::list
// -------------------------
std::list<int> lst = {10, 15, 20, 25, 30};
auto big = filter(lst, [](int x) { return x > 20; });
print(lst, "Original list");
print(big, "Filtered >20");
}
/*
OUTPUT:
Original nums: 1 2 3 4 5 6
Filtered evens: 2 4 6
Original words: the world hi universe
Filtered long words: world universe
Original list: 10 15 20 25 30
Filtered >20: 25 30
*/