विषय पर बढ़ें

अंतिम अद्यतन:2026-10-12

C++20 Ranges लाइब्रेरी

ranges, C++20 की प्रमुख विशेषताओं में से एक है, जिसमें "view" काफ़ी महत्वपूर्ण हिस्सा है। C++20 से पहले, स्टैंडर्ड लाइब्रेरी के एल्गोरिद्म iterators पर आधारित थे, उदाहरण के लिए: std::sort।

std::sort(v.begin() + 2, v.end())

Iterator + algorithm मिलकर कुछ जटिल ऑपरेशन कर सकते हैं, उदाहरण के लिए: मैं उल्टा क्रम (descending) चाहता हूँ:

std::sort(v.rbegin(), v.rend())

लेकिन इसके साथ कुछ समस्याएँ भी हैं:

  • दो असंगत iterators को आसानी से मिला देना।
  • एल्गोरिद्मों की संयोजन क्षमता बहुत कमज़ोर, कुछ मध्यवर्ती वेरिएबल संग्रहीत करने पड़ते हैं

उदाहरण के लिए: अब एक student information system है, हम उम्र 21-25 के बीच और GPA >= 3.5, शर्त पूरी करने वाले छात्रों का कुल GPA निकालना चाहते हैं। C++17 से पहले हम नीचे जैसा pseudo-code लिख सकते थे:

std::vector<Student> students
std::vector<Student> selected;
std::copy_if(students.begin(), students.end(), std::back_inserter(selected),
             [](const Student& student) {
               return student.age >= 21 && student.age <= 25 && student.gpa >= 3.5;
             });

double s = std::accumulate(
    selected.begin(), selected.end(), 0.0,
    [](double sum, const Student& student) { return sum + student.gpa; });

देखा जा सकता है कि शर्त पूरी करने वाले छात्रों की जानकारी छानते समय हमें उसे selected में copy करना पड़ता है, फिर उसका योग निकालना पड़ता है।

C++20 ने एक अधिक संक्षिप्त और कुशल लिखने का तरीका पेश किया, ranges और pipe ऑपरेटर | से कई ऑपरेशन जोड़कर, बिना मध्यवर्ती वेरिएबल के सीधे योग निकाला जा सकता है, उदाहरण के लिए:

double s = 0.0;
for (const auto& student :
     students | std::views::filter([](const auto& s) {
       return s.age >= 21 && s.age <= 25 && s.gpa >= 3.5;
     }) | std::views::transform([](const auto& s) { return s.gpa; })) {
  s += student;
}

देखा जा सकता है कि कई एल्गोरिद्म बिना किसी व्यवधान के जुड़े हैं, मध्यवर्ती temporary वेरिएबल की मेमोरी आवंटन कम हुआ, पठनीयता भी बहुत बढ़ी, pipe | से भिन्न ऑपरेशन एक साथ जुड़ते हैं।

आगे, चलिए C++20 ranges से जुड़ी सामग्री पर चर्चा करते हैं।

1. मूल अवधारणाएँ

1.range

range एक अनुक्रम (sequence) दर्शाने वाली अमूर्त अवधारणा है। यह कोई भी iterator वाला कंटेनर हो सकता है या कोई ऐसा ऑब्जेक्ट जिसमें begin() और end() फ़ंक्शन परिभाषित हों। जैसे std::vector, std::list आदि ranges के उदाहरण हैं। Arrays को भी range माना जा सकता है।

2.view

view, Range का केवल-पढ़ने योग्य (read-only) पहुँच है। यह lazy evaluation का तरीका है, केवल ज़रूरत के समय गणना होती है, इसका अर्थ है कि यह वास्तव में डेटा संग्रहीत नहीं करता। उदाहरण के लिए: std::views::filter और std::views::transform view के प्रमुख उदाहरण हैं। ये हमें range पर छँटाई और रूपांतरण की सुविधा देते हैं, बिना नया कंटेनर बनाए।

3.algorithm

एल्गोरिद्म वे फ़ंक्शन हैं जो range या view पर ऑपरेशन करते हैं, उदाहरण के लिए: std::sort, std::find आदि एल्गोरिद्म के उदाहरण हैं।

4.|

Pipe ऑपरेटर |, views और एल्गोरिद्मों को जोड़ सकता है, बाईं ओर का परिणाम दाईं ओर के input के रूप में देता है। इससे कोड अधिक स्पष्ट और संक्षिप्त होता है। उदाहरण के लिए: students | std::views::filter(...) द्वारा students range को std::views::filter को छँटाई के लिए दिया जाता है, फिर परिणाम अगले ऑपरेशन को दिया जाता है।

ऊपर वाले student गणना का उदाहरण लें, इस उदाहरण में हमने students range को | द्वारा view filter के input के रूप में दिया, फिर परिणाम को view transform के input के रूप में दिया, अंत में एक range लौटाया, उस range पर loop चलाकर, accumulation एल्गोरिद्म से योग निकाला।

double s = 0.0;
for (const auto& student :
     students | std::views::filter([](const auto& s) {
       return s.age >= 21 && s.age <= 25 && s.gpa >= 3.5;
     }) | std::views::transform([](const auto& s) { return s.gpa; })) {
  s += student;
}

देखा जा सकता है कि range के इस तरह फ़ायदे हैं:

  • कोड की पठनीयता बढ़ती है
  • Lazy evaluation: Ranges ने view की अवधारणा पेश की, जो lazy evaluation की अनुमति देती है, यानी परिणाम केवल ज़रूरत के समय गणना होता है।

उदाहरण के लिए: केवल *v.begin() के समय गणना होगी।

auto v = std::views::reverse(vec);
std::cout << *v.begin() << std::endl;
  • त्रुटियाँ कम: Ranges का डिज़ाइन पारंपरिक iterator ऑपरेशनों की आम त्रुटियाँ कम करने में मदद करता है, जैसे असंगत iterators का उपयोग।
  • आदि।

Range अवधारणा ने भिन्न प्रकार के ranges का वर्णन करने के लिए अलग-अलग concepts पेश किए। ये concepts generic programming में ranges की विशेषताएँ समझने और सीमित करने में मदद करते हैं। निम्नलिखित कुछ आम range concepts हैं:

https://en.cppreference.com/w/cpp/ranges

Concept विवरण कंटेनर उदाहरण
std::ranges::input_range शुरू से अंत तक कम से कम एक बार iterate हो सकता है std::forward_list, std::list, std::duque, std::array, std::vector
std::ranges::forward_range शुरू से अंत तक कई बार iterate हो सकता है std::forward_list, std::list, std::duque, std::array, std::vector
std::ranges::bidirectional_range iterator -- से पीछे भी जा सकता है std::list, std::duque, std::array, std::vector
std::ranges::random_access_range constant समय में element पर jump कर सकते हैं [] std::duque, std::array, std::vector
std::ranges::contiguous_range elements सदा मेमोरी में लगातार संग्रहीत रहते हैं std::array, std::vector

2. उपयोग

यह विशेषता उपयोग करना काफ़ी सरल है, केवल header file शामिल करके, इंटरफ़ेस का उपयोग करें।

उदाहरण के लिए: संख्याओं के ढेर में से even numbers छाँटना।

#include <ranges>
auto evenNumbers = numbers | std::views::filter([](int x) { return x % 2 == 0; });

Compile: केवल -std निर्दिष्ट करें।

g++ -std=c++20 main.cc -o main

कंपाइलर समर्थन के लिए नीचे की सूची देखें:

https://en.cppreference.com/w/cpp/compiler_support/20

gcc >=10, clang >=13 (partial), >=15 पूर्ण समर्थन।

संबंधित विषय

टिप्पणियाँ