Deducing Types
- 1. Template Type Deduction (Item 1)
- 2. Auto Type Deduction (Item 2)
- 3. Decltype (Item 3)
- 4. Viewing Deduced Types (Item 4)
- Multiple-Choice Questions
- Design Questions
- Test Cases
- Test 1: Array Decay
- Test 2: Universal Reference Deduction
- Test 3: decltype Behavior
- Answers and Explanations
- Multiple-Choice Answers
- Design Answers
1. Template Type Deduction (Item 1)
- Three Cases:
ParamTypeis a reference/pointer (not universal reference):- Ignore references in
expr; match remaining type toParamType.
template<typename T> void f(T& param); const int cx = 0; f(cx); // T = const int, param = const int&- Ignore references in
ParamTypeis a universal reference (T&&):- Lvalues deduce
Tas lvalue reference; rvalues deduceTas non-reference.
template<typename T> void f(T&& param); int x = 0; f(x); // T = int&, param = int& (lvalue) f(27); // T = int, param = int&& (rvalue)- Lvalues deduce
ParamTypeis by-value (neither pointer nor reference):- Strip
const/volatile; decay arrays/functions to pointers.
template<typename T> void f(T param); const char arr[] = "test"; f(arr); // T = const char* (array decays to pointer)- Strip
2. Auto Type Deduction (Item 2)
- Follows template deduction rules except for braced initializers:
auto x = {1, 2, 3}; // x = std::initializer_list<int> template<typename T> void f(T param); f({1, 2, 3}); // Error: cannot deduce T
3. Decltype (Item 3)
decltypereturns the declared type of an entity or expression:int x = 0; decltype(x) y = x; // y = int decltype((x)) z = y; // z = int& (expression (x) is lvalue)
4. Viewing Deduced Types (Item 4)
- Use
typeid(may strip references) orBoost.TypeIndex:#include <boost/type_index.hpp> template<typename T> void printType() {std::cout << boost::typeindex::type_id_with_cvr<T>().pretty_name(); }
Multiple-Choice Questions
-
What is the type of
paramintemplate<typename T> void f(T&& param)when called withint x = 0; f(x);?- A)
int - B)
int& - C)
int&& - D)
const int&
Answer: B)
int&
Explanation:xis an lvalue; universal reference deducesTasint&. - A)
-
Given
const char name[] = "Hello"; auto arr = name;, what isarr’s type?- A)
const char* - B)
const char[6] - C)
const char(&)[6] - D)
char*
Answer: A)
const char*
Explanation: Arrays decay to pointers in by-valueautodeduction. - A)
-
Which code causes a compilation error?
// 1: auto x = {1}; // 2: template<typename T> void f(T param); f({1});- A) 1
- B) 2
- C) Both
- D) Neither
Answer: B) 2
Explanation: Braced initializers cannot deduceTin templates.
-
What is
decltype((x))ifint x = 0;?- A)
int - B)
int& - C)
int&& - D)
const int
Answer: B)
int&
Explanation:(x)is an lvalue expression;decltypeyieldsint&. - A)
-
Which code deduces
Tasint[3]?int arr[3]; // 1: template<typename T> void f(T& param); f(arr); // 2: template<typename T> void f(T param); f(arr);- A) 1
- B) 2
- C) Both
- D) Neither
Answer: A) 1
Explanation: References preserve array types; by-value decays to pointer.
Design Questions
- Write a template function
arraySizereturning the size of an array.template<typename T, size_t N> constexpr size_t arraySize(T (&)[N]) { return N; }int main() {int arr[] = {1, 2, 3};static_assert(arraySize(arr) == 3); }
- Use
decltypeto declare a reference variableybound toxwithoutauto&.int x = 10; decltype((x)) y = x; // y = int&
- Fix the error in
print({1, 2, 3}):// Original (error): template<typename T> void print(T param) {} print({1, 2, 3});// Fixed: void print(std::initializer_list<int> param) {}
- Design a
forwarderto perfectly forward arguments.template<typename F, typename... Args> auto forwarder(F&& func, Args&&... args) {return std::forward<F>(func)(std::forward<Args>(args)...); }
- Create a type trait
IsReferenceto detect references.template<typename T> struct IsReference : std::false_type {};template<typename T> struct IsReference<T&> : std::true_type {};template<typename T> struct IsReference<T&&> : std::true_type {};
Test Cases
Test 1: Array Decay
#include <iostream>
#include <type_traits>template<typename T>
void checkArray(T param) {if (std::is_array_v<T>)std::cout << "Array preserved!\n";elsestd::cout << "Array decayed to pointer.\n";
}int main() {int arr[3];checkArray(arr); // Output: "Array decayed to pointer."
}
Test 2: Universal Reference Deduction
#include <iostream>
#include <type_traits>template<typename T>
void checkRef(T&& param) {if (std::is_lvalue_reference_v<T&&>)std::cout << "Lvalue reference\n";elsestd::cout << "Rvalue reference\n";
}int main() {int x = 0;checkRef(x); // Lvalue referencecheckRef(27); // Rvalue reference
}
Test 3: decltype Behavior
#include <iostream>
#include <type_traits>int main() {int x = 0;decltype((x)) y = x; // y = int&static_assert(std::is_same_v<decltype(y), int&>);
}
Answers and Explanations
Multiple-Choice Answers
- B - Universal reference with lvalue deduces to lvalue reference.
- A - By-value
autodecays arrays to pointers. - B - Braced initializers cannot deduce template types.
- B -
decltypeon lvalue expression yields reference. - A - References preserve array types.
Design Answers
arraySizeuses reference to deduce array size.decltype((x))captures lvalue reference.- Explicit
std::initializer_listfixes template deduction. forwarderuses perfect forwarding.IsReferencespecializes forT&andT&&.
