You need to be clear on what you want to achieve; how should be your second question. You can use polymorphism to avoid writing new code, or you can use it to avoid changing old code.
If all you want is a class or a function to behave differently for different types, then static polymorphism will do the trick. Sometimes plain function overload will be enough; sometimes you will have to use templates; occasionally you will have to specialise your templates for edge cases. This mostly tackles the issue of writing new, redundant code: why write IntVectors and StringVectors if a compiler can write them for you.
You should derive classes only when you want to refer to them through a base class pointer. Dynamic polymorphism allows you to reuse existing code without modifying it: if you have a function that displays widgets on screen, you don't need to rewrite it when you introduce a new type of widget.
Now, if you can combine static and dynamic polymorphism, you've got the power. A random example that comes to mind is a spreadsheet, but it might not be the best:
class BaseCell {
// ...
public:
virtual void draw() = 0;
};
template<class CellFormat>
class Cell : public BaseCell {
public:
virtual void draw(); // uses something supplied by CellFormat
};
// somewhere else
vector<shared_ptr<BaseCell>> cells {
shared_ptr<BaseCell>{new Cell<IntFormat>()},
shared_ptr<BaseCell>{new Cell<CurrencyFormat>()}
};
for (auto cell: cells) {
cell->draw();
}
In this way you can write future proof functions that use BaseCell provided interface, reducing changes to the existing codebase, and generate different classes for new supported formats, reducing new code that has to be written.
To sum up: runtime and static polymorphism are not substitutes, but they are complementing techniques that share the idea of uniform interface to different behaviours.