CodeNebula
C++20stladvanced

std::predicate (C++20 Addition)

C++20 · The Big Four · Compiler flag: -std=c++20

Explanation

Concept that refines `regular_invocable` to require the return type to be convertible to `bool`. Models functions that answer a yes/no question about their arguments.

Real-World Scenario

Constrain a filter function to only accept callables that return a boolean result.

Quick Snippet

snippet.cpp
#include <concepts>
#include <vector>

template<typename T, std::predicate<const T&> Pred>
std::vector<T> filter(const std::vector<T>& items, Pred pred) {
    std::vector<T> result;
    for (auto& item : items)
        if (pred(item)) result.push_back(item);
    return result;
}

auto positives = filter(numbers, [](int n) { return n > 0; });

Full Example

predicate.cpp
// CodeNebula - C++20 Example: std::predicate Concept
// Compile: g++ -std=c++20 -Wall -Wextra -o example predicate.cpp

// std::predicate<F, Args...> refines std::regular_invocable by requiring
// that the callable returns a boolean-testable value. Predicates are the
// foundation of algorithms like filter, find_if, and count_if.

#include <concepts>
#include <functional>
#include <iostream>
#include <string>
#include <vector>

// Filter elements matching a predicate
template <typename T, std::predicate<T> Pred>
std::vector<T> filter(const std::vector<T>& items, Pred pred) {
    std::vector<T> result;
    for (const auto& item : items) {
        if (std::invoke(pred, item)) {
            result.push_back(item);
        }
    }
    return result;
}

// Count elements matching a predicate
template <typename T, std::predicate<T> Pred>
std::size_t count_if(const std::vector<T>& items, Pred pred) {
    std::size_t count = 0;
    for (const auto& item : items)
        if (std::invoke(pred, item)) ++count;
    return count;
}

// Check if any element matches
template <typename T, std::predicate<T> Pred>
bool any_of(const std::vector<T>& items, Pred pred) {
    for (const auto& item : items)
        if (std::invoke(pred, item)) return true;
    return false;
}

// Named predicates
bool is_positive(int x) { return x > 0; }

struct IsLongerThan {
    std::size_t min_len;
    bool operator()(const std::string& s) const { return s.size() > min_len; }
};

int main() {
    // Filter integers
    std::vector<int> nums = {-3, -1, 0, 2, 5, -4, 8, 1};

    auto positives = filter(nums, is_positive);
    std::cout << "Positives: ";
    for (int n : positives) std::cout << n << " ";
    std::cout << "\n";

    auto evens = filter(nums, [](int x) { return x % 2 == 0; });
    std::cout << "Evens: ";
    for (int n : evens) std::cout << n << " ";
    std::cout << "\n";

    // Count with predicate
    std::cout << "Count positive: " << count_if(nums, is_positive) << "\n";
    std::cout << "Count negative: "
              << count_if(nums, [](int x) { return x < 0; }) << "\n";

    // Filter strings with function object predicate
    std::vector<std::string> words = {"hi", "hello", "hey", "greetings", "yo"};
    auto long_words = filter(words, IsLongerThan{3});
    std::cout << "\nWords longer than 3: ";
    for (const auto& w : long_words) std::cout << w << " ";
    std::cout << "\n";

    // any_of
    std::cout << "Any negative? " << any_of(nums, [](int x) { return x < 0; }) << "\n";
    std::cout << "Any > 100? " << any_of(nums, [](int x) { return x > 100; }) << "\n";

    return 0;
}

// Expected output:
// Positives: 2 5 8 1
// Evens: 0 2 -4 8
// Count positive: 4
// Count negative: 3
//
// Words longer than 3: hello greetings
//
// Any negative? 1
// Any > 100? 0
Run command
g++ -std=c++20 -Wall -Wextra -o example predicate.cpp