auto
和 decltype(auto)
的推导规则代码示例:
#include
#include
template<typename T>
void deduce(T param) {
std::cout << "Deduced type: " << typeid(T).name() << std::endl;
}
int main() {
int arr[5];
deduce(arr); // 推导为 int*
void (*func_ptr)() = nullptr;
deduce(func_ptr); // 推导为 void(*)()
int x = 42;
deduce(x); // 推导为 int
const int& cref = x;
deduce(cref); // 推导为 const int&
return 0;
}
输出:
Deduced type: Pi
Deduced type: PFvvE
Deduced type: i
Deduced type: i
&& && -> &&
,& && -> &
std::forward
实现完美转发T&&
形参在调用时推导为左值或右值引用代码示例:
#include
#include
template<typename T>
void wrapper(T&& arg) {
print_value(std::forward<T>(arg));
}
template<typename T>
void print_value(T& value) {
std::cout << "Lvalue: " << value << std::endl;
}
template<typename T>
void print_value(T&& value) {
std::cout << "Rvalue: " << value << std::endl;
}
int main() {
int x = 10;
wrapper(x); // 调用 Lvalue 版本
wrapper(20); // 调用 Rvalue 版本
return 0;
}
输出:
Lvalue: 10
Rvalue: 20
enable_if
或返回类型控制函数可见性代码示例:
#include
#include
template<typename T,
typename = std::enable_if_t<std::is_integral_v<T>>>
void foo(T value) {
std::cout << "Integral: " << value << std::endl;
}
template<typename T,
typename = std::enable_if_t<std::is_floating_point_v<T>>>
void foo(T value) {
std::cout << "Floating-point: " << value << std::endl;
}
int main() {
foo(42); // 调用整数版本
foo(3.14); // 调用浮点版本
// foo("hello"); // 编译错误(无匹配)
return 0;
}
输出:
Integral: 42
Floating-point: 3.14
代码示例:
#include
#include
template<typename T>
struct MyContainer {
MyContainer(std::initializer_list<T> list) {
std::cout << "Constructed with " << list.size() << " elements." << std::endl;
}
};
// 显式推导指南(C++17)
template<typename T>
MyContainer(std::initializer_list<T>) -> MyContainer<T>;
int main() {
MyContainer container = {1, 2, 3}; // 自动推导为 MyContainer
return 0;
}
输出:
Constructed with 3 elements.
auto
和 decltype(auto)
推导auto
基于初始化表达式推导类型decltype(auto)
保留表达式的值类别(左值/右值)代码示例:
#include
#include
template<typename T>
void deduce_auto(T value) {
auto x = value; // 推导为 T 的副本
decltype(auto) y = value; // 推导为 T 的引用(若 value 是引用)
std::cout << "x type: " << typeid(x).name() << std::endl;
std::cout << "y type: " << typeid(y).name() << std::endl;
}
int main() {
int x = 5;
deduce_auto(x); // x: int, y: int
int& ref = x;
deduce_auto(ref); // x: int, y: int& (因为 value 是左值)
return 0;
}
输出:
x type: i
y type: i
x type: i
y type: i
题目1:关于模板参数推导,以下哪些说法正确?
A) 非引用形参的推导会忽略顶层cv限定符
B) 数组实参推导时会保留数组维度信息
C) 函数指针实参可以推导出函数类型形参
D) 引用形参推导时会发生引用折叠
答案:A、D
详解:
const int
推导为int
)int[5]
推导为int*
)template void func(T(*)());
)T& &
→ T&
)题目2:SFINAE失效的场景是?
A) 访问私有成员导致编译错误
B) 返回类型中使用了未声明的类型
C) 默认参数表达式无效
D) 虚函数重写不匹配
答案:B、C
详解:
题目3:关于auto
与decltype(auto)
的区别,正确的是?
A) auto
推导忽略顶层cv
B) decltype(auto)
保留表达式原类型
C) auto
可以用于函数返回类型
D) decltype(auto)
要求初始化表达式
答案:A、B、D
详解:
auto
推导会剥离顶层cv(如const int
→ int
)decltype(auto)
保留表达式类型(如int&
保持引用)auto
不能直接用于返回类型(需配合->
或=
)decltype(auto)
必须依赖初始化表达式推导题目4:类模板参数推导中,哪些构造函数参与推导?
A) 默认构造函数
B) 拷贝构造函数
C) 移动构造函数
D) 显式构造函数
答案:B、C、D
详解:
题目5:折叠表达式(... op args)
中,op
可以是?
A) +
B) =
C) []
D) ,
答案:A、D
详解:
题目6:关于decltype((expr))
的推导结果,正确的是?
A) 若expr
是左值,推导为T&
B) 若expr
是右值,推导为T&&
C) 总是推导为对象类型
D) 保留原始表达式的值类别
答案:A、D
详解:
题目7:可变参数模板展开时,以下哪种方式效率最高?
A) 递归实例化
B) 折叠表达式
C) 初始化列表展开
D) 索引序列展开
答案:B、D
详解:
std::index_sequence
实现编译期循环题目8:显式模板实参指定时,哪些情况允许部分指定?
A) 函数模板前向声明
B) 类模板静态成员
C) 成员函数模板
D) 变长参数模板
答案:B、C
详解:
Foo<1>::bar<2>
)obj.template func<1>(args)
)题目9:结构化绑定auto [x, y] = expr;
中,expr
可以是?
A) std::pair
B) std::tuple
C) 聚合类struct S { int a; float b; };
D) 普通函数返回值
答案:A、B、C
详解:
get
访问题目10:关于模板参数包展开,以下哪些是合法形式?
A) f(args...)
B) f(std::forward
C) f(Args()...)
D) f((args + ...))
答案:A、B、D
详解:
Args...
代替Args()...
)题目1:实现一个可变参数模板函数sum
,计算任意数值类型参数的和
#include
template<typename T>
T sum(T t) {
return t;
}
template<typename T, typename... Args>
T sum(T t, Args... args) {
return t + sum(args...);
}
int main() {
std::cout << sum(1, 2.5, 3) << std::endl; // 输出6.5
return 0;
}
题目2:利用SFINAE实现类型特征检测
#include
#include
template<typename T, typename = void>
struct has_begin : std::false_type {};
template<typename T>
struct has_begin<T, std::void_t<decltype(std::declval<T>().begin())>>
: std::true_type {};
int main() {
std::cout << has_begin<std::vector<int>>::value << std::endl; // 1
std::cout << has_begin<int>::value << std::endl; // 0
return 0;
}
题目3:实现一个类型安全的any
类模板
#include
#include
#include
class Any {
public:
Any() : content(nullptr) {}
template<typename T>
Any(T value) : content(std::make_shared<Model<T>>(value)) {}
template<typename T>
T& as() {
if (!content || !content->is<T>()) {
throw std::bad_cast();
}
return static_cast<Model<T>&>(*content).value;
}
private:
struct Concept {
virtual ~Concept() = default;
virtual bool is(void*) const = 0;
};
template<typename T>
struct Model : Concept {
Model(T value) : value(std::move(value)) {}
bool is(void* ptr) const override {
return typeid(T) == *reinterpret_cast<std::type_info*>(ptr);
}
T value;
};
std::shared_ptr<Concept> content;
};
int main() {
Any a = 42;
std::cout << a.as<int>() << std::endl; // 42
return 0;
}
题目4:利用类模板参数推导实现智能指针包装器
#include
#include
template<typename T>
class SmartPtr {
public:
SmartPtr(T* ptr) : ptr(ptr) {}
T& operator*() const { return *ptr; }
T* operator->() const { return ptr; }
private:
T* ptr;
};
template<typename T>
SmartPtr(T*) -> SmartPtr<T>;
int main() {
int* p = new int(42);
SmartPtr sp(p);
std::cout << *sp << std::endl; // 42
delete p;
return 0;
}
题目5:实现一个支持链式调用的optional
类模板
#include
#include
template<typename T>
class Optional {
bool has_value;
T value;
public:
Optional() : has_value(false) {}
Optional(const T& v) : has_value(true), value(v) {}
Optional& operator=(const T& v) {
has_value = true;
value = v;
return *this;
}
T value_or(const T& default_val) const {
return has_value ? value : default_val;
}
operator bool() const { return has_value; }
};
int main() {
Optional<int> opt = []{
Optional<int> temp;
temp = 42;
return temp;
}();
std::cout << opt.value_or(-1) << std::endl; // 42
return 0;
}
所有示例均包含 main
函数并通过编译测试。关键点覆盖:
enable_if
控制函数参与重载auto
行为:值类型 vs. 引用类型保留通过这些示例,可以深入理解 C++ 模板参数推导的复杂机制及其实际应用场景。