C++20stladvanced
std::views::empty / std::ranges::empty_view (C++20 Addition)
C++20 · The Big Four · Compiler flag: -std=c++20
Explanation
A view that contains zero elements of a given type. Useful as a default/sentinel value in APIs that return views, or as the base case in recursive range algorithms.
Real-World Scenario
Return an empty view from a search function when no results are found, avoiding nullable return types.
Quick Snippet
snippet.cpp
#include <ranges>
auto no_results() -> std::ranges::empty_view<int> {
return {};
}
for (int x : no_results()) { /* never executes */ }Full Example
ranges_empty_view.cpp
// CodeNebula - C++20 Example: std::ranges::empty_view
// Compile: g++ -std=c++20 -Wall -Wextra -o example ranges_empty_view.cpp
#include <iostream>
#include <ranges>
#include <vector>
#include <string>
#include <algorithm>
// Function that returns a view - empty_view as default/sentinel
auto get_data(bool available) {
static std::vector<int> data = {10, 20, 30, 40, 50};
if (available)
return std::ranges::subrange(data.begin(), data.end());
else
return std::ranges::subrange(data.end(), data.end());
}
int main() {
// empty_view contains no elements of a given type
std::ranges::empty_view<int> empty_ints;
std::cout << "Empty view size: " << std::ranges::size(empty_ints) << "\n";
std::cout << "Empty view is empty: " << std::boolalpha
<< std::ranges::empty(empty_ints) << "\n";
std::cout << "Data pointer: " << empty_ints.data() << "\n";
// Using views::empty
auto ev = std::views::empty<double>;
std::cout << "\nEmpty<double> size: " << std::ranges::size(ev) << "\n";
// Iteration over empty view does nothing
std::cout << "Iterating empty view: [";
for (int n : std::views::empty<int>)
std::cout << n; // Never executes
std::cout << "]\n";
// empty_view satisfies range concepts
static_assert(std::ranges::range<std::ranges::empty_view<int>>);
static_assert(std::ranges::sized_range<std::ranges::empty_view<int>>);
static_assert(std::ranges::contiguous_range<std::ranges::empty_view<int>>);
std::cout << "\nSatisfies range: true\n";
std::cout << "Satisfies sized_range: true\n";
std::cout << "Satisfies contiguous_range: true\n";
// Useful as a no-op in generic code
auto process = [](auto&& rng) {
int count = 0;
for ([[maybe_unused]] auto&& elem : rng) ++count;
return count;
};
std::vector<int> nums = {1, 2, 3};
std::cout << "\nProcess vector: " << process(nums) << " elements\n";
std::cout << "Process empty: " << process(std::views::empty<int>) << " elements\n";
// Use in conditional data retrieval
std::cout << "\nWith data: ";
for (int n : get_data(true)) std::cout << n << " ";
std::cout << "\nWithout data: ";
for (int n : get_data(false)) std::cout << n << " ";
std::cout << "(nothing)\n";
return 0;
}
Run command
g++ -std=c++20 -Wall -Wextra -o example ranges_empty_view.cpp