టెంప్లేట్లు & Generic Programming

🌐 Modern C++ (C++20/C++17) 🟢 Chapter 18 of 20 📂 Phase 05: అడ్వాన్స్‌డ్ C++, STL & ప్రాజెక్ట్ 📅 2026 Edition
📌 Covered in this chapter: Function Templates · Class Templates · Non-type Template Parameters · Template Specialization · Concepts & Constraints (C++20)

ఆధునిక సాఫ్ట్‌వేర్ అభివృద్ధిలో ఒకే లాజిక్‌ను పూర్ణాంకాలు (int), దశాంశాలు (double), అక్షరాలు (char) లేదా కస్టమ్ ఆబ్జెక్టుల కోసం వేర్వేరుగా పదే పదే రాయడం అనేది సమయం మరియు మానవ శ్రమను వృధా చేయడమే. ఈ సమస్యకు C++ అందించిన అద్భుతమైన మరియు అసమానమైన పరిష్కారమే టెంప్లేట్లు (Templates) & జెనరిక్ ప్రోగ్రామింగ్ (Generic Programming).

ఇతర ప్రోగ్రామింగ్ భాషల్లో (Java Generics లేదా C# వంటివి) జెనరిక్స్ రన్‌టైమ్‌లో బాక్సింగ్/అన్‌బాక్సింగ్ మరియు టైప్-ఎరేజర్ (Type Erasure) ద్వారా పనిచేసి పనితీరును తగ్గిస్తాయి. కానీ C++ లో టెంప్లేట్లు కంపైల్-టైమ్ కోడ్ జనరేషన్ (Compile-time Monomorphization) ద్వారా పనిచేస్తాయి! ఫలితంగా సున్నా రన్‌టైమ్ ఓవర్‌హెడ్ (Zero Runtime Overhead) తో చేతితో రాసిన మెషిన్ అసెంబ్లీ కోడ్ అంతే వేగంతో అమలవుతాయి. అంతేకాకుండా Modern C++20 లో ప్రవేశపెట్టిన విప్లవాత్మకమైన Concepts & Constraints టెంప్లేట్ ప్రోగ్రామింగ్‌ను మరింత సురక్షితంగా మరియు సులభంగా మార్చాయి.

ఈ సమగ్ర మాస్టర్‌క్లాస్‌లో మనం Function & Class Templates, Non-type Template Parameters (NTTP), Template Specialization, Variadic Templates (C++11/C++17 Fold Expressions), C++20 Concepts & requires నిబంధనలు, మరియు పూర్తి స్థాయి "Enterprise High-Performance Generic Lock-Free Ring Buffer Engine" ప్రాజెక్ట్‌ను ప్రత్యక్షంగా నిర్మించి నేర్చుకుందాం!

1 జెనరిక్ ప్రోగ్రామింగ్ అంటే ఏమిటి? (Code Generation Automation)

జెనరిక్ ప్రోగ్రామింగ్ (Generic Programming) అంటే ఏమిటి? నిర్దిష్టమైన డేటా టైప్‌లతో (int, string, double) సంబంధం లేకుండా, ఒక సాధారణ బ్లూప్రింట్ (Type-Agnostic Algorithm) రాసి, ఏ డేటా టైప్‌కైనా సరిపోయేలా కోడ్‌ను రూపొందించే పద్ధతిని జెనరిక్ ప్రోగ్రామింగ్ అంటారు.

C++ లో ఈ జెనరిక్ ఫిలాసఫీని సాధ్యం చేసే సాధనాలే టెంప్లేట్లు (Templates).

టెంప్లేట్లు ఎలా పనిచేస్తాయి?
మీరు టెంప్లేట్ రాసినప్పుడు కంపైలర్ నేరుగా మెషిన్ కోడ్‌ను సృష్టించదు! మీరు ప్రోగ్రామ్‌లో ఆ టెంప్లేట్‌ను int తో పిలిస్తే, కంపైలర్ వెనుక వైపు int వెర్షన్ ఫంక్షన్‌ను ఆటోమేటిక్‌గా టైప్ చేస్తుంది; మీరు double తో పిలిస్తే double వెర్షన్‌ను రూపొందిస్తుంది. ఈ ప్రక్రియను Template Instantiation అంటారు.

2 ఫంక్షన్ టెంప్లేట్లు (Function Templates: template )

రెండు విలువలలో ఏది పెద్దదో కనుగొనడానికి సాధారణంగా మనం int max(int, int), double max(double, double) అని విడివిడిగా రాస్తుంటాం. కానీ ఫంక్షన్ టెంప్లేట్‌తో ఒక్కటే సరిపోతుంది:

template <typename T>
T getMaximum(T a, T b) {
    return (a > b) ? a : b;
}

ఇక్కడ typename మరియు class కీవర్డ్లు రెండూ సరిగ్గా ఒకే విధంగా పనిచేస్తాయి (రెంటిలో దేనినైనా వాడవచ్చు).

function_template_basics.cpp
#include <iostream>
#include <string>

// జెనరిక్ ఫంక్షన్ టెంప్లేట్
template <typename T>
T findMax(T a, T b) {
    return (a > b) ? a : b;
}

// బహుళ విభిన్న టైప్‌ల టెంప్లేట్ (Multi-type Template)
template <typename T, typename U>
void printPair(T first, U second) {
    std::cout << "జత: [" << first << ", " << second << "]\n";
}

int main() {
    std::cout << "పూర్ణాంకాల గరిష్టం (int):   " << findMax(25, 42) << "\n";
    std::cout << "దశాంశాల గరిష్టం (double): " << findMax(99.45, 12.30) << "\n";
    std::cout << "అక్షరాల గరిష్టం (string): " << findMax(std::string("Hyderabad"), std::string("Bengaluru")) << "\n";

    std::cout << "\nబహుళ టైప్ జతలు:\n";
    printPair("RollNo", 101);
    printPair(3.14159, "PI Value");
    return 0;
}

3 క్లాస్ టెంప్లేట్లు (Class Templates: Generic Containers)

ఏ డేటా టైప్‌నైనా భద్రపరచగల జెనరిక్ డేటా స్ట్రక్చర్‌లను (ఉదాహరణకు std::vector<T>, std::stack<T>) రూపొందించడానికి క్లాస్ టెంప్లేట్లు ఉపయోగపడతాయి.

generic_container_class.cpp
#include <iostream>
#include <string>

// జెనరిక్ క్లాస్ టెంప్లేట్
template <typename T>
class SecureBox {
private:
    T content;
public:
    SecureBox(T val) : content(val) {}

    void setContent(T val) { content = val; }
    T getContent() const { return content; }

    void inspect() const {
        std::cout << "  📦 [SecureBox] డేటా విలువ: " << content 
                  << " (సైజ్: " << sizeof(content) << " Bytes)\n";
    }
};

int main() {
    SecureBox<int> intBox(5000);
    SecureBox<double> dblBox(999.85);
    SecureBox<std::string> strBox("Secret-Bank-Vault-Token");

    intBox.inspect();
    dblBox.inspect();
    strBox.inspect();
    return 0;
}

4 Non-Type Template Parameters (NTTP)

టెంప్లేట్లలో కేవలం డేటా టైప్‌లనే కాకుండా, పూర్ణాంక సంఖ్యలను (Integers, Pointers, Enums) కూడా టెంప్లేట్ పారామీటర్‌గా పాస్ చేయవచ్చు. దీనినే Non-Type Template Parameter (NTTP) అంటారు.

ఉపయోగం: కంపైల్-టైమ్‌లోనే ఫిక్స్‌డ్ సైజ్ కలిగిన మెమరీ బఫర్‌లను సృష్టించి, హీప్ మెమరీ అలొకేషన్ ఓవర్‌హెడ్‌ను పూర్తిగా నివారించవచ్చు (ఉదాహరణకు std::array<T, N>).

nttp_fixed_buffer.cpp
#include <iostream>

// T అనేది డేటా టైప్, Size అనేది NTTP సంఖ్య!
template <typename T, size_t Size>
class StaticStack {
private:
    T buffer[Size];
    size_t count = 0;

public:
    bool push(const T& val) {
        if (count >= Size) return false;
        buffer[count++] = val;
        return true;
    }

    T pop() {
        if (count == 0) throw std::underflow_error("స్టాక్ ఖాళీగా ఉంది!");
        return buffer[--count];
    }

    size_t capacity() const { return Size; }
    size_t size() const { return count; }
};

int main() {
    // 5 ఎలిమెంట్ల ఫిక్స్‌డ్ సైజ్ స్టాక్ (హీప్ అలొకేషన్ లేదు - 100% స్టాక్ మెమరీ!)
    StaticStack<int, 5> fastStack;
    fastStack.push(10);
    fastStack.push(20);
    fastStack.push(30);

    std::cout << "స్టాక్ సామర్థ్యం: " << fastStack.capacity() << " | ఎలిమెంట్లు: " << fastStack.size() << "\n";
    std::cout << "పాప్ చేసిన విలువ: " << fastStack.pop() << "\n";
    return 0;
}

5 టెంప్లేట్ స్పెషలైజేషన్ (Full & Partial Specialization)

సాధారణ జెనరిక్ నియమం అన్ని టైప్‌లకూ సరిపోయినప్పటికీ, ఏదైనా ఒక నిర్దిష్ట డేటా టైప్ కోసం ప్రత్యేకమైన ఆప్టిమైజ్డ్ లాజిక్ అవసరమైనప్పుడు టెంప్లేట్ స్పెషలైజేషన్ (Template Specialization) ను ఉపయోగిస్తాం.

  • Full Specialization: టెంప్లేట్ పారామీటర్లను పూర్తిగా ఒక నిర్దిష్ట టైప్‌కు కట్టబెట్టడం: template <> class MyBox<bool> { ... };
  • Partial Specialization: పాయింటర్ల కోసం లేదా పాక్షిక టైప్‌ల కోసం స్పెషలైజ్ చేయడం: template <typename T> class MyBox<T*> { ... };
template_specialization_demo.cpp
#include <iostream>

// 1. సాధారణ జెనరిక్ టెంప్లేట్
template <typename T>
class Formatter {
public:
    static void print(T val) {
        std::cout << "  [సాధారణ ఫార్మాట్]: " << val << "\n";
    }
};

// 2. Full Specialization for bool (0/1 కాకుండా True/False ప్రింట్ కొరకు)
template <>
class Formatter<bool> {
public:
    static void print(bool val) {
        std::cout << "  [బూలియన్ స్పెషలైజ్డ్ ఫార్మాట్]: " << (val ? "TRUE (నిజం)" : "FALSE (అబద్ధం)") << "\n";
    }
};

int main() {
    Formatter<int>::print(100);
    Formatter<double>::print(3.14);
    Formatter<bool>::print(true); // స్పెషలైజ్డ్ వెర్షన్ అమలవుతుంది!
    return 0;
}

6 డీఫాల్ట్ టెంప్లేట్ ఆర్గుమెంట్లు (Default Template Arguments)

ఒక టెంప్లేట్‌ను ఉపయోగించేటప్పుడు ప్రోగ్రామర్ టైప్‌ను స్పష్టంగా చెప్పకపోతే కంపైలర్ డిఫాల్ట్‌గా ఒక టైప్‌ను తీసుకోవడానికి మనం డీఫాల్ట్ ఆర్గుమెంట్లను ఇవ్వవచ్చు:

template <typename T = double, size_t Capacity = 64>
class RingBuffer { ... };

ఇప్పుడు RingBuffer<> buf; అని రాస్తే అది ఆటోమేటిక్‌గా double మరియు 64 సైజుతో ఇన్‌స్టాన్షియేట్ అవుతుంది.

7 వేరియాడిక్ టెంప్లేట్లు & C++17 Fold Expressions

వేరియాడిక్ టెంప్లేట్లు (Variadic Templates - C++11): ఎన్ని ఆర్గుమెంట్లనైనా (0, 1, 5, లేదా 100) స్వీకరించగల జెనరిక్ ఫంక్షన్లను రూపొందించడానికి typename... Args (Parameter Pack) ను ఉపయోగిస్తాం.

Modern C++17 Fold Expressions: పాత C++11 లో పారామీటర్ ప్యాక్‌ను లెక్కించడానికి రికర్సివ్ ఫంక్షన్లు రాయాల్సి వచ్చేది. కానీ C++17 లో (args + ...) అనే ఒక్క చిన్న సమీకరణంతో మొత్తం ప్యాక్‌ను అద్భుతంగా సమ్మేషన్ చేయవచ్చు!

fold_expressions_c17.cpp
#include <iostream>

// C++17 Fold Expression ద్వారా ఎన్ని సంఖ్యలనైనా ఒక్క లైన్‌లో కూడటం!
template <typename... Args>
auto sumAll(Args... args) {
    return (args + ...); // Unary Right Fold: (a1 + (a2 + (a3 + ...)))
}

int main() {
    std::cout << "3 సంఖ్యల మొత్తం:  " << sumAll(10, 20, 30) << "\n";
    std::cout << "5 సంఖ్యల మొత్తం:  " << sumAll(1.5, 2.5, 3.0, 4.0, 5.0) << "\n";
    std::cout << "స్ట్రింగ్స్ కలయిక: " << sumAll(std::string("C++20 "), std::string("Fold "), std::string("Magic!")) << "\n";
    return 0;
}

8 కంపైల్-టైమ్ ప్రోగ్రామింగ్ & if constexpr (C++17)

రన్‌టైమ్‌లో if-else కండిషన్లను చెక్ చేస్తే ప్రోగ్రామ్ స్పీడ్ తగ్గుతుంది. కానీ if constexpr ద్వారా కంపైల్-టైమ్‌లోనే కండిషన్ తనిఖీ చేయబడి, తప్పుడు బ్రాంచ్ కోడ్ అసలు బైనరీ ఫైల్‌లోకే రాకుండా పూర్తిగా తొలగించబడుతుంది (Dead Code Elimination)!

if_constexpr_demo.cpp
#include <iostream>
#include <type_traits>

template <typename T>
void processData(T val) {
    if constexpr (std::is_pointer_v<T>) {
        std::cout << "  పాయింటర్ డేటా డీరిఫరెన్స్: " << *val << "\n";
    } else {
        std::cout << "  డైరెక్ట్ వాల్యూ డేటా: " << val << "\n";
    }
}

int main() {
    int num = 42;
    processData(num);  // else బ్రాంచ్ మాత్రమే కంపైల్ అవుతుంది!
    processData(&num); // if బ్రాంచ్ మాత్రమే కంపైల్ అవుతుంది!
    return 0;
}

9 Modern C++20 విప్లవం: Concepts & Constraints (requires)

C++ చరిత్రలో గత 30 ఏళ్లుగా టెంప్లేట్ ప్రోగ్రామర్లను వేధించిన అతిపెద్ద సమస్య: క్రిప్టిక్ ఎర్రర్ మెసేజ్‌లు (Cryptic Compiler Errors). ఒక టెంప్లేట్ ఫంక్షన్‌కు తప్పుడు టైప్ పాస్ చేస్తే 500 లైన్ల అర్థం కాని ఎర్రర్ వచ్చేది!

ఈ సమస్యకు Modern C++20 లో లభించిన విప్లవాత్మక పరిష్కారమే Concepts & Constraints.

"టెంప్లేట్ ఏ టైప్‌నైనా గుడ్డిగా తీసుకోకూడదు! కేవలం నిర్దిష్ట నిబంధనలను (ఉదా: సంఖ్యలు మాత్రమే, లేదా కూడటం సాధ్యమయ్యే టైప్స్ మాత్రమే) సంతృప్తిపరిస్తేనే అనుమతించాలి!"
cpp20_concepts_demo.cpp
#include <iostream>
#include <concepts>

// C++20 Standard Concept: std::integral (పూర్ణాంకాలు మాత్రమే!)
template <std::integral T>
T computeModulo(T a, T b) {
    return a % b;
}

// Custom Concept: నంబర్లు (int లేదా float) మాత్రమే
template <typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;

template <Numeric T>
T average(T a, T b) {
    return (a + b) / 2;
}

int main() {
    std::cout << "Modulo (15 % 4): " << computeModulo(15, 4) << "\n";
    // computeModulo(15.5, 4.2); // ❌ కంపైలర్ క్లీన్ ఎర్రర్: Constraints not satisfied!

    std::cout << "Average: " << average(10.5, 20.5) << "\n";
    return 0;
}

10 టెంప్లేట్స్ హెడర్-ఓన్లీ స్వభావం & Code Bloat నివారణ

హెడర్-ఓన్లీ రూల్ (The Header-Only Rule):
సాధారణ C++ ఫంక్షన్లలా కాకుండా, టెంప్లేట్ల యొక్క పూర్తి డిక్లరేషన్ మరియు ఇంప్లిమెంటేషన్‌ను తప్పనిసరిగా హెడర్ ఫైల్స్ (.hpp / .h) లోనే ఉంచాలి! ఎందుకంటే వేరే ఫైల్ టెంప్లేట్‌ను పిలిచినప్పుడు కంపైలర్‌కు ఆ టైప్ కొరకు కొత్త కోడ్‌ను సృష్టించడానికి పూర్తి టెంప్లేట్ బాడీ కంటికి కనిపించాలి.

కోడ్ బ్లోట్ (Code Bloat): టెంప్లేట్లను 100 వేర్వేరు టైప్‌లతో వాడితే బైనరీ ఎగ్జిక్యూటబుల్ సైజు పెరుగుతుంది. దీనిని నివారించడానికి కామన్ లాజిక్‌ను నాన్-టెంప్లేట్ బేస్ క్లాస్‌లో ఉంచడం ప్రొఫెషనల్ పద్ధతి.

11 సాధారణ టెంప్లేట్ తప్పులు & డీబగ్గింగ్ గైడ్

  1. Dependent Names లో typename మర్చిపోవడం: టెంప్లేట్ లోపల వేరొక టైప్‌ను యాక్సెస్ చేసేటప్పుడు (ఉదా: T::iterator) కంపైలర్‌కు అది వేరియబుల్ కాదని చెప్పడానికి typename T::iterator అని రాయాలి.
  2. టెంప్లేట్ డెఫినిషన్‌ను .cpp లో దాచిపెట్టడం: దీనివల్ల లింకర్ ఎర్రర్ (Undefined Reference) వస్తుంది.

12 రియల్-వరల్డ్ ప్రాజెక్ట్: Enterprise High-Performance Generic Lock-Free Ring Buffer Engine

నిజ జీవితంలో హై-స్పీడ్ ఆడియో ఇంజిన్లు (FL Studio, ProTools), ఆటోమోటివ్ CAN-Bus నెట్‌వర్క్‌లు మరియు హై-ఫ్రీక్వెన్సీ ట్రేడింగ్ సిస్టమ్స్ సెకనుకు లక్షలాది మెసేజ్‌లను జీరో హీప్ అలొకేషన్ మరియు జీరో లాక్‌లతో పాస్ చేయడానికి రింగ్ బఫర్ (Circular Queue) ను ఉపయోగిస్తాయి.

ఈ సమగ్ర ప్రాజెక్ట్‌లో మనం C++20 Concepts, Non-type Template Parameters, మరియు కంపైల్-టైమ్ సైజ్ నిర్ధారణతో కూడిన ఒక ఎంటర్‌ప్రైజ్ జెనరిక్ రింగ్ బఫర్ ఇంజిన్ ను నిర్మిస్తున్నాం:

GenericRingBufferEngine.cpp
#include <iostream>
#include <string>
#include <type_traits>
#include <concepts>
#include <optional>

// C++20 Concept: కాపీ కన్‌స్ట్రక్ట్ చేయగల టైప్‌లకు మాత్రమే అనుమతి!
template <typename T>
concept Bufferable = std::is_copy_constructible_v<T>;

// జెనరిక్ రింగ్ బఫర్ క్లాస్ టెంప్లేట్ విత్ NTTP Capacity
template <Bufferable T, size_t Capacity>
class RingBuffer {
    static_assert(Capacity > 0, "❌ బఫర్ కెపాసిటీ ఖచ్చితంగా 0 కంటే ఎక్కువ ఉండాలి!");

private:
    T buffer[Capacity]; // ఫిక్స్‌డ్ సైజ్ స్టాక్ బఫర్ (జీరో హీప్ ఓవర్‌హెడ్!)
    size_t head = 0;
    size_t tail = 0;
    size_t currentSize = 0;

public:
    RingBuffer() = default;

    bool enqueue(const T& item) {
        if (currentSize == Capacity) {
            return false; // బఫర్ ఫుల్!
        }
        buffer[tail] = item;
        tail = (tail + 1) % Capacity;
        currentSize++;
        return true;
    }

    std::optional<T> dequeue() {
        if (currentSize == 0) {
            return std::nullopt; // బఫర్ ఖాళీ!
        }
        T item = buffer[head];
        head = (head + 1) % Capacity;
        currentSize--;
        return item;
    }

    size_t size() const { return currentSize; }
    size_t maxCapacity() const { return Capacity; }
    bool isEmpty() const { return currentSize == 0; }
    bool isFull() const { return currentSize == Capacity; }
};

struct TelemetryLog {
    int sensorId;
    double reading;
};

int main() {
    std::cout << "=======================================================================\n";
    std::cout << "🔄 [ENTERPRISE GENERIC RING BUFFER & CIRCULAR QUEUE ENGINE]\n";
    std::cout << "=======================================================================\n";

    // 1. పూర్ణాంకాల (int) రింగ్ బఫర్ (సామర్థ్యం: 4)
    RingBuffer<int, 4> intQueue;
    std::cout << "\n[టెస్ట్ 1: పూర్ణాంకాల రింగ్ బఫర్ (Capacity: 4)]:\n";
    intQueue.enqueue(101);
    intQueue.enqueue(102);
    intQueue.enqueue(103);
    intQueue.enqueue(104);

    if (!intQueue.enqueue(105)) {
        std::cout << "  ⚠️ బఫర్ నిండిపోయింది (105 డ్రాప్ చేయబడింది!)\n";
    }

    while (!intQueue.isEmpty()) {
        std::cout << "  రీడ్ చేసిన ఐటెమ్: " << *intQueue.dequeue() << "\n";
    }

    // 2. కస్టమ్ స్ట్రక్చర్ (TelemetryLog) రింగ్ బఫర్
    RingBuffer<TelemetryLog, 3> telemetryQueue;
    std::cout << "\n[టెస్ట్ 2: జెనరిక్ టెలిమెట్రీ సెన్సార్ స్ట్రీమ్]:\n";
    telemetryQueue.enqueue({0xAA1, 38.4});
    telemetryQueue.enqueue({0xAA2, 42.1});

    while (auto item = telemetryQueue.dequeue()) {
        std::cout << "  📡 సెన్సార్ ID: 0x" << std::hex << item->sensorId 
                  << std::dec << " | ఉష్ణోగ్రత: " << item->reading << " °C\n";
    }

    std::cout << "\n=======================================================================\n";
    std::cout << "✅ C++20 Concepts తో జెనరిక్ రింగ్ బఫర్ ఎగ్జిక్యూషన్ విజయవంతమైంది!\n";
    std::cout << "=======================================================================\n";
    return 0;
}

13 సారాంశం & ఇంటరాక్టివ్ క్విజ్ (Summary & Self-Check Quizzes)

📌 ఈ అధ్యాయంలో నేర్చుకున్న ప్రధాన అంశాలు:

  • Generic Programming: డేటా టైప్‌తో సంబంధం లేకుండా టైప్-ఇండిపెండెంట్ కోడ్ రాసే శక్తి.
  • Template Instantiation: కంపైలర్ మనం వాడే ప్రతి టైప్ కొరకు కంపైల్-టైమ్‌లోనే అసలు మెషిన్ కోడ్‌ను ఉచితంగా సృష్టిస్తుంది (Zero Runtime Overhead).
  • NTTP (Non-Type Template Parameters): సైజులు, సంఖ్యలను టెంప్లేట్ ఆర్గుమెంట్లుగా పాస్ చేసి ఫిక్స్‌డ్ సైజ్ బఫర్లను నిర్మించడం.
  • Template Specialization: నిర్దిష్ట డేటా టైప్‌ల కొరకు (ఉదా: bool) ప్రత్యేకమైన ఆప్టిమైజ్డ్ లాజిక్ అందించడం.
  • Fold Expressions (C++17): వేరియాడిక్ పారామీటర్ ప్యాక్‌ను రికర్షన్ లేకుండా (args + ...) తో సింపుల్‌గా ఎవాల్యుయేట్ చేయడం.
  • if constexpr (C++17): కంపైల్-టైమ్ బ్రాంచింగ్ ద్వారా అనవసరమైన కోడ్ బ్రాంచ్‌ను పూర్తిగా తొలగించడం.
  • Concepts & Constraints (C++20): టెంప్లేట్ టైప్‌లపై కచ్చితమైన నిబంధనలు విధించి క్రిప్టిక్ ఎర్రర్లను రూపుమాపడం.
  • Header-Only Rule: టెంప్లేట్ ఫంక్షన్ల పూర్తి కోడ్‌ను ఎల్లప్పుడూ హెడర్ ఫైళ్లలోనే ఉంచాలి.

🧠 మీ అవగాహనను పరీక్షించుకోండి (5 Interactive Quizzes):

ప్రశ్న 1: C++ టెంప్లేట్లు ఇతర భాషల జెనరిక్స్ (Java Generics) కంటే ఎందుకు మెరుపు వేగంతో పనిచేస్తాయి?
సమాధానం: కంపైల్-టైమ్ మోనోమార్ఫైజేషన్ (Compile-time Code Generation) వల్ల సున్నా రన్‌టైమ్ ఓవర్‌హెడ్ ఉండటం చేత!
వివరణ: Java లో రన్‌టైమ్‌లో ఆబ్జెక్ట్ కాస్టింగ్ మరియు బాక్సింగ్ జరుగుతుంది. C++ లో కంపైలర్ ప్రతి టైప్‌కు విడివిడిగా అత్యుత్తమ అసెంబ్లీ మెషిన్ కోడ్‌ను ముందే ఉత్పత్తి చేస్తుంది, ఫలితంగా రన్‌టైమ్ పెనాల్టీ సున్నా.
ప్రశ్న 2: టెంప్లేట్ డెఫినిషన్లను .cpp ఫైల్‌లో కాకుండా హెడర్ ఫైల్స్ (.hpp) లోనే ఎందుకు రాయాలి?
సమాధానం: కంపైలర్ కొత్త టైప్ కొరకు కోడ్‌ను ఇన్‌స్టాన్షియేట్ చేయడానికి టెంప్లేట్ బాడీ మొత్తం కంటికి కనిపించాలి కాబట్టి!
వివరణ: వేరొక ట్రాన్స్‌లేషన్ యూనిట్ లో టెంప్లేట్‌ను కాల్ చేసినప్పుడు బాడీ .cpp లో దాగి ఉంటే కంపైలర్ కోడ్ జనింపజేయలేదు; ఫలితంగా లింకింగ్ సమయంలో undefined reference ఎర్రర్ వస్తుంది.
ప్రశ్న 3: Non-Type Template Parameter (NTTP) అంటే ఏమిటి?
సమాధానం: డేటా టైప్‌కు బదులుగా పూర్ణాంక సంఖ్యలను లేదా కంపైల్-టైమ్ స్థిరరాశులను టెంప్లేట్ పారామీటర్‌గా పాస్ చేయడం!
వివరణ: ఉదాహరణకు template <typename T, size_t N> class Array లో N అనేది NTTP. దీనివల్ల కంపైల్-టైమ్‌లోనే ఫిక్స్‌డ్ సైజ్ కేటాయించబడి మెమరీ వేగం పెరుగుతుంది.
ప్రశ్న 4: Modern C++20 లో Concepts ప్రవేశపెట్టడానికి గల ప్రధాన కారణం ఏమిటి?
సమాధానం: టెంప్లేట్ టైప్‌లపై కచ్చితమైన నిబంధనలు (Constraints) విధించి, క్రిప్టిక్ కంపైలర్ ఎర్రర్లను క్లీన్‌గా మార్చడానికి!
వివరణ: తప్పుడు టైప్ పాస్ చేసినప్పుడు వందల కొద్దీ లైన్ల లోపాలు రాకుండా, కంపైలర్ "Constraints not satisfied" అని స్పష్టమైన సూటి ఎర్రర్ ఇస్తుంది.
ప్రశ్న 5: C++17 లోని if constexpr సాధారణ if కంటే ఎలా భిన్నమైనది?
సమాధానం: if constexpr కంపైల్-టైమ్‌లోనే కండిషన్‌ను లెక్కించి, తప్పుడు బ్రాంచ్‌ను అసలు బైనరీ లోకే రాకుండా తొలగిస్తుంది!
వివరణ: సాధారణ if రన్‌టైమ్‌లో చెక్ అవుతుంది మరియు రెండు బ్రాంచ్‌ల కోడ్ బైనరీలో ఉంటుంది. if constexpr లో కంపైలర్ కేవలం సరైన బ్రాంచ్‌ను మాత్రమే కంపైల్ చేసి మిగిలిన దాన్ని డెడ్ కోడ్‌గా పారేస్తుంది.
← మునుపటి అధ్యాయం: 17. ఆపరేటర్ ఓవర్‌లోడింగ్ తర్వాతి అధ్యాయం: 19. STL కంటైనర్లు →

ఈ ప్రాజెక్ట్‌ను లైవ్‌గా మన కంపైలర్‌లో రన్ చేయండి!

ఎటువంటి లోకల్ సెటప్ లేకుండా, బ్రౌజర్‌లోనే నేరుగా Modern C++ (GCC 13 / C++20) కంపైలర్‌లో ఈ కోడ్‌ను ఎగ్జిక్యూట్ చేసి రన్‌టైమ్ అవుట్‌పుట్‌ను తనిఖీ చేయండి.