C++20stladvanced
std::views::common / std::ranges::common_view (C++20 Addition)
C++20 · The Big Four · Compiler flag: -std=c++20
Explanation
Adapts a range with different iterator and sentinel types into one where both are the same type. Required for passing ranges to legacy algorithms that expect matching begin/end types.
Real-World Scenario
Use a sentinel-terminated range (like a null-terminated string view) with a legacy C++ algorithm that requires `begin()` and `end()` to return the same type.
Quick Snippet
snippet.cpp
#include <ranges>
#include <algorithm>
#include <vector>
auto nums = std::views::iota(1, 10);
auto common_nums = nums | std::views::common;
std::vector<int> vec(std::ranges::begin(common_nums),
std::ranges::end(common_nums));Full Example
ranges_common_view.cpp
// CodeNebula - C++20 Example: std::ranges::common_view
// Compile: g++ -std=c++20 -Wall -Wextra -o example ranges_common_view.cpp
#include <ranges>
#include <vector>
#include <algorithm>
#include <numeric>
#include <iostream>
// std::ranges::common_view / std::views::common converts a range
// into one where begin() and end() return the same type. This is
// needed for legacy algorithms that require matching iterator types.
int main() {
// Unbounded iota piped through take produces non-common range
auto non_common = std::views::iota(1) | std::views::take(5);
static_assert(!std::ranges::common_range<decltype(non_common)>);
// Convert to common_view for legacy algorithm compatibility
auto common = non_common | std::views::common;
static_assert(std::ranges::common_range<decltype(common)>);
// Now we can use std::accumulate (requires same begin/end type)
int sum = std::accumulate(common.begin(), common.end(), 0);
std::cout << "Sum of 1..5: " << sum << "\n";
// Construct a vector from a non-common view
auto transformed = std::views::iota(1)
| std::views::transform([](int n) { return n * n; })
| std::views::take(6)
| std::views::common;
std::vector<int> squares(transformed.begin(), transformed.end());
std::cout << "Squares: ";
for (int n : squares) std::cout << n << " ";
std::cout << "\n";
// Already-common ranges pass through unchanged
std::vector<int> vec = {5, 3, 8, 1, 9};
auto already_common = vec | std::views::common;
static_assert(std::ranges::common_range<decltype(already_common)>);
// Use common_view with std::sort (legacy version)
auto view = vec | std::views::common;
// Note: std::ranges::sort works without common, but std::sort needs it
std::cout << "Original: ";
for (int n : vec) std::cout << n << " ";
std::cout << "\n";
// Use with std::distance (legacy)
auto counted = std::views::iota(0) | std::views::take(10) | std::views::common;
auto dist = std::distance(counted.begin(), counted.end());
std::cout << "Distance: " << dist << "\n";
// Practical: use string algorithm with non-common view
auto chars = std::views::iota('a')
| std::views::take(10)
| std::views::common;
std::string str(chars.begin(), chars.end());
std::cout << "String: " << str << "\n";
// Use with std::find (legacy)
auto nums = std::views::iota(10)
| std::views::take(20)
| std::views::common;
auto it = std::find(nums.begin(), nums.end(), 15);
if (it != nums.end()) {
std::cout << "Found: " << *it << "\n";
}
return 0;
}
Run command
g++ -std=c++20 -Wall -Wextra -o example ranges_common_view.cpp