Skip to Content
Course content

216: Common C++ Interview Questions on Templates

Click on the "Edit" button in the top corner of the screen to edit your slide content.

If you're heading into a C++ interview, you can bet your life that templates will come up. Interviewers love them because templates are where the "magic" happens—and where most developers get confused. They aren't just looking to see if you can write template <typename T>; they want to see if you understand how the compiler actually instantiates those templates and how you can control that process.

Instead of just listing questions and answers, let's build a SmartPrinter. This is a classic interview-style problem: creating a utility that behaves differently based on the type it's handling. We'll hit on full specialization, partial specialization, and the dreaded SFINAE (Substitution Failure Is Not An Error).

Starting with a Basic Generic Printer

First, I'll start with a simple primary template. This is our "catch-all." If no specialized version exists, the compiler falls back to this. I'm using a class template here because it gives us more flexibility for specialization than a standalone function template would.

#include <iostream>
#include <string>
#include <type_traits>

template <typename T>
struct SmartPrinter {
    void print(const T& value) {
        std::cout << "Generic value: " << value << std::endl;
    }
};

Handling Specific Types with Full Specialization

Now, let's say we want bool values to print as "True" or "False" instead of "1" or "0". This is where full specialization comes in. You're telling the compiler: "If T is exactly bool, ignore the primary template and use this specific implementation instead."

template <>
struct SmartPrinter<bool> {
    void print(const bool& value) {
        std::cout << "Boolean value: " << (value ? "True" : "False") << std::endl;
    }
};

The Trap of Partial Member Specialization

Here is where I usually see candidates trip up—and where I've tripped up myself in the past. Let's say I want a version of SmartPrinter that handles all pointer types (int*, char*, etc.) by printing the memory address.

My first instinct might be to try and specialize just the print method inside the primary template. I'll write it out here, but don't do this:

// MISTAKE: This will not compile as partial specialization
template <typename T>
struct SmartPrinter {
    void print(const T& value) { std::cout << value << std::endl; }

    template <typename U>
    void print(U* ptr) { // Attempting partial specialization of a member
        std::cout << "Pointer address: " << ptr << std::endl;
    }
};

The compiler will scream at me. In C++, you cannot partially specialize a member function. You can overload it, but that's not the same as template specialization. To fix this, I have to partially specialize the entire class. This is a key distinction that interviewers watch for.

// CORRECT: Partial specialization of the class
template <typename T>
struct SmartPrinter<T*> {
    void print(T* value) {
        std::cout << "Pointer address: " << value << std::endl;
    }
};

Using SFINAE to Filter by Type Category

Finally, let's talk about SFINAE. You'll often hear this term in interviews. It basically means that if a template substitution results in an invalid type, the compiler doesn't throw a hard error; it just quietly removes that template from the list of candidates.

I want a version of the printer that only works for numeric types (integers, floats). I'll use std::enable_if. I'm going to add this as a separate overload to show how we can "disable" templates based on type traits.

template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value, void>
printNumeric(T value) {
    std::cout << "Numeric value: " << value << std::endl;
}

Wait, if I put that in my SmartPrinter class, I can make it even cleaner. Let's look at how the final piece fits together. By combining a primary template, a full specialization for bool, a partial specialization for pointers, and a trait-based check for numbers, we've covered 90% of the template questions you'll face.

// Putting it all together
int main() {
    SmartPrinter<int> p1;
    p1.print(10);       // Uses primary (or we could add an arithmetic specialization)

    SmartPrinter<bool> p2;
    p2.print(true);     // Uses full specialization: "Boolean value: True"

    int x = 5;
    SmartPrinter<int*> p3;
    p3.print(&x);     // Uses partial specialization: "Pointer address: 0x..."
    
    return 0;
}



📋 Practical Task

Building a Floating-Point Precision Guard

In this exercise, you will create a template-based utility called PrecisionPrinter. Your goal is to demonstrate your ability to use std::enable_if and std::is_floating_point to create a specialized behavior for floating-point numbers while maintaining a generic fallback for other types.

Requirements:

  • Create a primary template PrecisionPrinter<T> with a print(T value) method that outputs: "Standard value: [value]".
  • Use SFINAE (std::enable_if and std::is_floating_point) to create a version of the print logic that only activates for float or double. This version should output: "High-precision float: [value]".
  • Implement a full specialization for std::string that outputs: "String literal: [value]".
  • Test your implementation with an int, a double, and a std::string to verify that the compiler selects the correct overload/specialization for each.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.