-1

I am quite new to the topic of templates in C++. Why in the following toy example code do we have to precede the class's and each function's name with template <class T> (meaning why do we need it, at all)?

Is it possible to modify the code not to use template <class T> everywhere?

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>

using namespace std;

template <class T>
class Stack {   private:
    vector<T> elements;

  public:
    void push(T const &);
    void pop();
    T top();
    bool empty(); };

template <class T>
void Stack<T>::push(T const &elem) {
    elements.push_back(elem); }

template <class T>
void Stack<T>::pop() {
    if (elements.empty()) {
        throw out_of_range("Stack<>::pop(): empty stack");
    } else {
        elements.pop_back();
    }
}

template <class T>
T Stack<T>::top() {
    if (empty()) {
        throw out_of_range("Stack<>::top(): empty stack");
    }
    return elements.back();
}

template <class T>
bool Stack<T>::empty() {
    return elements.empty();
}


int main() {
    try {
        Stack<int> intStack;       // Stack of ints
        Stack<string> stringStack; // Stack of strings

        // Manipulate integer stack
        intStack.push(7);
        cout << intStack.top() << endl;

        // Manipulate string stack
        stringStack.push("hello");
        cout << stringStack.top() << std::endl;
        stringStack.pop();
        stringStack.pop();
    }
    catch (exception const &ex) {
        cerr << "Exception: " << ex.what() << endl;
        return -1;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
cerebrou
  • 5,353
  • 15
  • 48
  • 80
  • 5
    What is "template header"? – Teivaz Jun 21 '17 at 07:27
  • There are no headers for template. If you don't want to use template the define two class for two different data types `std::string` and `int`. – P0W Jun 21 '17 at 07:28
  • By "template header" I mean `template `. How should I call it then? I said I'm new to the topic. Please be more understandable. – cerebrou Jun 21 '17 at 07:35
  • 2
    @cerebrou Yes you can do that by replacing all occurences of `T` with a concrete type like `int` or `double`. But why would you want to do so? It makes the class less useful. – πάντα ῥεῖ Jun 21 '17 at 07:42
  • 1
    New to the topic of templates in C++? Start [here](https://stackoverflow.com/q/388242/1889329). – IInspectable Jun 21 '17 at 08:30
  • 2
    Q: "Why do we have to precede the class's and each function's name with `template `"? A: Because that's the syntax for templates. Q: What are templates, why do we need them, and how do we use them? A: This is too broad here. – bolov Jun 21 '17 at 08:54
  • @bolov what part of the OP's question makes you think they are asking the second, and not the first? – Caleth Jun 21 '17 at 11:44
  • @Caleth The OP is asking for the first. But that answer to that is "because that's how you declare template" and then I feel like this just slides into question 2. It's like asking why do we write `int a = 5`. The answer is because that's how we declare a variable, and then of course it comes: "Ok, now please explain what are variables" – bolov Jun 21 '17 at 11:57
  • OP also asks "can I write this template without N+1 copies of `template `, for N members", which *isn't* "please explain templates" – Caleth Jun 21 '17 at 12:06
  • 2
    I believe the question is not too brad at all. The OP is not familiar with the inline method implementations (implementation inside class), and he/she just noticed that the the "usual" way of defining the methods has a lot of repetitive syntax in the case of templates. Asking how to get rid of that syntax is pretty legitimate. –  Jun 21 '17 at 13:14
  • @Caleth: You are referring to a different revision of the question than others are. That one *may* be more reasonable. The first incarnation certainly was just a waste of everyone's time. – IInspectable Jun 21 '17 at 14:12
  • I saw the first incarnation, which I didn't think was a waste of time. I thought it needed some clarity of terminology – Caleth Jun 21 '17 at 14:39

2 Answers2

11

C++ is a statically typed language.

Since this is the case, say I wanted a function to check the minimum or maximum of two values.

I could create a function like the following:

int max(int a, int b) { return (a > b) ? a : b; }

But this only works for int types. If I want one for a double or uint64_t or FooBarClass, I would need to create additional functions:

double max(double a, double b) { return (a > b) ? a : b; }
uint64_t max(uint64_t a, uint64_t b) { return (a > b) ? a : b; }
FooBarClass max(FooBarClass a, FooBarClass b) { return (a > b) ? a : b; }

Why in the following toy example code do we have to precede the class's and each function's name with template ?

In C++, a template is a way to introduce a concept known as "generics". With generics, you no longer need to concern your self with creating a function for each type, the type will be deduced from the template function signature.

So instead, I could write the following:

template < typename T > // the typename or class keywords are synonymous when declaring a template
T max(T a, T b) { return (a > b) ? a : b; }

The inclusion of template < typename T > to the function signature indicates to the compiler that this function is a "generic" function and must be processed accordingly.

If, on the other hand, you just had the following:

T max(T a, T b) { return (a > b) ? a : b; }

The compiler will expect T to be an explicit type (like typedef int T;).

A template can be applied to a class or function, and both at the same time:

template < typename T >
class Wrapper {
    public:
        Wrapper(const T& val) : _val(val) {}
        // ... other code

        template < typename X >
        operator X()
        {
            return static_cast<X>(this->_val);
        }

        T operator+(const T& val)
        {
            return this->_val + val;
        }

        friend std::ostream& operator<<(std::ostream& os, const Wrapper& val)
        {
            os << val._val;
            return os;
        }

    private:
        T _val;
};

int main(int argc, char* argv[])
{
    Wrapper<int> x(42);
    // template deduction will call Wrapper::operator X() with X being a double
    double d = x;
    // template deduction will call Wrapper::operator X() with X being a long
    long l = x;
    // this actually calls T operator+(const T& val) with val = 10 and T = int
    int i = x + 10;

    std::cout << "x = " << x << std::endl  // 42
              << "d = " << d << std::endl  // 42
              << "l = " << l << std::endl  // 42
              << "i = " << i << std::endl; // 52
    return 0;
}

You can also explicitly define a template type, this is known as template specialization and is beyond the scope of this answer given your understanding of templates at the current.

Is it possible to modify the code not to use template everywhere?

Yes and no. Yes, you can remove the template < class T > signature definition, but, as mentioned, the signature of the class/function takes on a completely different meaning.

Hope that clears up a little bit. Templates, when used properly, are a very powerful tool in C++.

txtechhelp
  • 6,625
  • 1
  • 30
  • 39
5

You have to include template <class T> in each member definition because that is part of the name of the member.

You can define the functions within the class-template body, for only one line with template <class T>

template <class T> 
class Stack {   
  private:
    vector<T> elements;

  public:
    void push(T const &) {
      elements.push_back(elem); }
    void pop() {
      if (elements.empty()) {
          throw out_of_range("Stack<>::pop(): empty stack");
      } else {
          elements.pop_back();
      } }
    T top() {
      if (empty()) {
          throw out_of_range("Stack<>::top(): empty stack");
      }
      return elements.back(); }
    bool empty() {
      return elements.empty(); } };
Caleth
  • 52,200
  • 2
  • 44
  • 75