Core Syntax Structure
The definition requires declaring type parameters before the class name. A typical implementation follows this pattern:
template<typename KeyType, typename ValueType>
class Entity
{
public:
Entity(KeyType id, ValueType data)
{
this->identifier = id;
this->metric = data;
}
void display() const
{
std::cout << "ID: " << this->identifier
<< " | Metric: " << this->metric << std::endl;
}
KeyType identifier;
ValueType metric;
};
void validateBasics()
{
Entity<std::string, int> user("User_A", 25);
user.display();
}
Comparison with Function Templates
Class templates enforce explicit type specification during construction; they do not infer types automatically like function templates. Additionally, default template parameters are supported.
template<typename KeyType, typename MetricType = int>
class Product
{
public:
Product(KeyType name, MetricType cost)
{
this->product_name = name;
this->price = cost;
}
void printProduct() const
{
std::cout << "Item: " << this->product_name
<< " Cost: " << this->price << std::endl;
}
KeyType product_name;
MetricType price;
};
void compareTemplates()
{
// Error: Cannot deduce KeyType and MetricType implicitly
// Product p1("Apple", 10);
// Success: Explicit template arguments required for instantiation
Product<std::string, int> p1("Apple", 10);
p1.printProduct();
// Success: Using default MetricType (int)
Product<std::string> p2("Orange", 15);
p2.printProduct();
}
Member Function Instantiation Scope
Definitions within a clas template remain ungenerated until the compielr encounters an actual usage scenario involving that specific member.
class HandlerA {
public:
void executeTaskA() { std::cout << "Task A Running" << std::endl; }
};
class HandlerB {
public:
void executeTaskB() { std::cout << "Task B Running" << std::endl; }
};
template<typename THandler>
class Manager {
public:
void runTask() { handler_.executeTaskA(); }
THandler handler_;
};
void instantiateManager()
{
Manager<HandlerA> mgr;
mgr.runTask();
// Calling undefined method results in compile-time error
}
Passing Template Instances to Functions
There are three primary methods for passing templated class objects into standard functions.
Method 1: Explicit Type Definition
Define the exact type in the function signature.
void processUser(Entity<std::string, int>& p)
{
p.display();
}
void demoMethod1()
{
Entity<std::string, int> e1("ID001", 500);
processUser(e1);
}
Method 2: Parameter Templatization
Ganeric function template accepting the class template types.
template<typename T1, typename T2>
void genericProcessor(Entity<T1, T2>& p)
{
p.display();
std::cout << "Types: " << typeid(T1).name() << " " << typeid(T2).name() << std::endl;
}
void demoMethod2()
{
Entity<std::string, int> e2("ID002", 600);
genericProcessor(e2);
}
Method 3: Entire Class Template Parameter
Pass the instantiated class type itself as the template argument.
template<typename TInstance>
void fullTemplatedHandler(TInstance& p)
{
p.display();
std::cout << "Full Type: " << typeid(TInstance).name() << std::endl;
}
void demoMethod3()
{
Entity<std::string, int> e3("ID003", 700);
fullTemplatedHandler(e3);
}