惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The GitHub Blog
The GitHub Blog
MyScale Blog
MyScale Blog
爱范儿
爱范儿
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
Y
Y Combinator Blog
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
Martin Fowler
Martin Fowler
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
M
MIT News - Artificial intelligence
博客园 - Franky
V
Visual Studio Blog
I
InfoQ
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
博客园 - 司徒正美
L
LangChain Blog

博客园 - double64

C# 字符串转换 C# 遍历删除空文件夹 MFC 单文档无边框最大化全屏 MFC 单文档去掉菜单栏 MFC 对话框去边框最大化全屏 C++ 动态数组 C++ 安全的拷贝赋值(Copy-and-Swap 惯用法) C++ 基类派生类的 static_cast 和 dynamic_cast 转换的简单测试 visual studio 的 snippet 代码片段模板样式 Windows 右键管理官方小程序Autoruns C++ 结合 enum 按位与或组合检测枚举项 std::unique_ptr 当删除器类型为 无状态的时构造可以不用传删除器示例 两个用来写 CLI - Command-Line Interface 的命令解析库 enum class 类型转换 int 微软输入法中如何输出当前时间 音程知识 英语 12 种时态 Qt 手动添加 Q_OBJECT 需要添加的地方 C# WPF 绑定 ObservableObject 实现 INotifyPropertyChanged 接口 C++ 标准库 copy_if C++ lambda 和 bind 何时优先使用 Windows 下的 Qt 中 min max 函数冲突 C++ RVO 或 NRVO 可能触发的条件 C++ std::unique_ptr 和 std::shared_ptr 都支持自定义删除器(deleter) C++ 智能指针和动态数组 std::vector 插入另一个 vector 的范围元素 Qt tableWidget QTableWidget 常用一些属性设置 C++ 内部类(嵌套类)是可以访问外部类的私有保护成员的 C++ 宏展开顺序 C++ std::round() 四舍五入
C++ 模板引用参数的各种情况
double64 · 2026-01-07 · via 博客园 - double64

帮我分析一下 C++ 模板引用参数的各种情况 -- to deepseek


我来详细分析 C++ 中模板引用参数的各种情况,包括值、引用、常引用、转发引用等。

1. 基础情况分析

情况1:按值传递模板参数

template<typename T>
void func_value(T param) {
    // param 是拷贝
    // T 被推导为去掉引用后的类型
}

int main() {
    int x = 10;
    const int cx = 20;
    int& rx = x;
    const int& crx = x;
    
    func_value(x);     // T = int, param = int
    func_value(cx);    // T = int, param = int (const 被忽略)
    func_value(rx);    // T = int, param = int (引用被忽略)
    func_value(crx);   // T = int, param = int (const和引用都被忽略)
    func_value(30);    // T = int, param = int (临时对象)
    
    return 0;
}

情况2:左值引用模板参数

template<typename T>
void func_lref(T& param) {
    // param 是左值引用
    // T 会被推导为原始类型
}

int main() {
    int x = 10;
    const int cx = 20;
    int& rx = x;
    const int& crx = x;
    
    func_lref(x);     // T = int, param = int&
    func_lref(cx);    // T = const int, param = const int&
    func_lref(rx);    // T = int, param = int&
    func_lref(crx);   // T = const int, param = const int&
    // func_lref(30); // ❌ 错误:不能绑定临时对象到非常量左值引用
    
    return 0;
}

情况3:常量左值引用模板参数

template<typename T>
void func_const_lref(const T& param) {
    // param 是常量左值引用
    // 可以接受任何类型
}

int main() {
    int x = 10;
    const int cx = 20;
    int& rx = x;
    const int& crx = x;
    
    func_const_lref(x);     // T = int, param = const int&
    func_const_lref(cx);    // T = int, param = const int&
    func_const_lref(rx);    // T = int, param = const int&
    func_const_lref(crx);   // T = int, param = const int&
    func_const_lref(30);    // ✅ T = int, param = const int&
    
    return 0;
}

情况4:万能引用(转发引用)

template<typename T>
void func_forwarding_ref(T&& param) {
    // 当 T 是推导类型时,T&& 是转发引用
    // 可以绑定到左值、右值、常量等
}

int main() {
    int x = 10;
    const int cx = 20;
    int& rx = x;
    const int& crx = x;
    
    func_forwarding_ref(x);     // T = int&, param = int& (左值引用)
    func_forwarding_ref(cx);    // T = const int&, param = const int&
    func_forwarding_ref(rx);    // T = int&, param = int&
    func_forwarding_ref(crx);   // T = const int&, param = const int&
    func_forwarding_ref(30);    // T = int, param = int&& (右值引用)
    
    // 注意:引用折叠规则
    // T& && 折叠为 T&
    // T&& & 折叠为 T&
    // T& & 折叠为 T&
    // T&& && 折叠为 T&&
    
    return 0;
}

2. 引用折叠的详细分析

#include <iostream>
#include <type_traits>

template<typename T>
void analyze_reference(T&& param) {
    std::cout << "T = " << typeid(T).name() 
              << ", param type = " << typeid(param).name()
              << ", is_lvalue_ref = " << std::is_lvalue_reference_v<decltype(param)>
              << ", is_rvalue_ref = " << std::is_rvalue_reference_v<decltype(param)>
              << std::endl;
}

int main() {
    int x = 10;
    const int cx = 20;
    
    std::cout << "=== 万能引用分析 ===\n";
    analyze_reference(x);      // T = int&, param = int&
    analyze_reference(cx);     // T = const int&, param = const int&
    analyze_reference(30);     // T = int, param = int&&
    
    // 显式指定类型(不是推导,所以不是万能引用)
    std::cout << "\n=== 显式指定类型 ===\n";
    analyze_reference<int>(x);   // T = int, param = int&& (右值引用)
    // 这里 x 会被强制转换为右值!
    
    return 0;
}

3. 完美转发(Perfect Forwarding)

#include <iostream>
#include <utility>

// 基础版本:不能完美转发
template<typename T>
void process_bad(T param) {
    std::cout << "process_bad: " << param << std::endl;
}

// 改进版本:使用万能引用
template<typename T>
void process_better(T&& param) {
    // 但是如何转发到其他函数?
    other_func(param);  // param 是左值,总是按左值传递
}

// 完美转发版本
template<typename T>
void process_perfect(T&& param) {
    // std::forward 保持值类别
    other_func(std::forward<T>(param));
}

void other_func(int& x) {
    std::cout << "lvalue: " << x << std::endl;
}

void other_func(int&& x) {
    std::cout << "rvalue: " << x << std::endl;
}

void other_func(const int& x) {
    std::cout << "const lvalue: " << x << std::endl;
}

int main() {
    int x = 10;
    const int cx = 20;
    
    std::cout << "=== 完美转发测试 ===\n";
    
    // 测试 process_better(不完美)
    // process_better(x);    // 调用 other_func(int&)
    // process_better(cx);   // 调用 other_func(const int&)
    // process_better(30);   // 调用 other_func(int&) ❌ 应该调用右值版本
    
    // 测试 process_perfect(完美转发)
    process_perfect(x);     // 转发为左值
    process_perfect(cx);    // 转发为常量左值
    process_perfect(30);    // 转发为右值
    
    return 0;
}

4. const 和 volatile 的推导规则

template<typename T>
void analyze(T param) {
    std::cout << "T deduced as: " << typeid(T).name() << std::endl;
}

template<typename T>
void analyze_ref(T& param) {
    std::cout << "T& deduced as: " << typeid(T).name() << std::endl;
}

template<typename T>
void analyze_const_ref(const T& param) {
    std::cout << "const T& deduced as: " << typeid(T).name() << std::endl;
}

int main() {
    const volatile int cv_x = 10;
    const volatile int& cv_ref = cv_x;
    
    std::cout << "=== CV 限定符推导 ===\n";
    
    // 按值传递:去掉顶层 cv 限定符
    analyze(cv_x);          // T = int
    analyze(cv_ref);        // T = int
    
    // 引用传递:保持底层 const
    analyze_ref(cv_x);      // T = const volatile int
    analyze_ref(cv_ref);    // T = const volatile int
    
    // const 引用传递
    analyze_const_ref(cv_x);    // T = int (const 已经在参数类型中)
    analyze_const_ref(cv_ref);  // T = int
    
    return 0;
}

5. 数组和函数的特殊处理

#include <iostream>

template<typename T>
void func_array_by_value(T param) {
    // 数组退化为指针
    std::cout << "size of param: " << sizeof(param) << std::endl;  // 指针大小
}

template<typename T, size_t N>
void func_array_by_ref(T (&param)[N]) {
    // 保持数组类型和大小
    std::cout << "size of param: " << sizeof(param) << std::endl;  // 数组大小
    std::cout << "array size N: " << N << std::endl;
}

void some_function(int, double) {}

template<typename T>
void func_func_by_value(T param) {
    // 函数退化为指针
    std::cout << "function pointer" << std::endl;
}

template<typename T>
void func_func_by_ref(T& param) {
    // 保持函数类型
    std::cout << "function reference" << std::endl;
}

int main() {
    int arr[10] = {0};
    std::cout << "=== 数组参数测试 ===\n";
    func_array_by_value(arr);    // T = int*, param = int*
    func_array_by_ref(arr);      // T = int, N = 10
    
    std::cout << "\n=== 函数参数测试 ===\n";
    func_func_by_value(some_function);   // T = void(*)(int, double)
    func_func_by_ref(some_function);     // T = void(int, double)
    
    return 0;
}

6. auto 推导的对比分析

#include <iostream>

int main() {
    int x = 10;
    const int cx = 20;
    int& rx = x;
    const int& crx = x;
    
    std::cout << "=== auto 推导 vs 模板推导 ===\n";
    
    // auto 按值推导(类似模板按值传递)
    auto a1 = x;     // auto = int
    auto a2 = cx;    // auto = int (const 被忽略)
    auto a3 = rx;    // auto = int (引用被忽略)
    auto a4 = crx;   // auto = int (const 和引用都被忽略)
    
    // auto 引用推导(类似模板引用传递)
    auto& b1 = x;     // auto = int
    auto& b2 = cx;    // auto = const int
    auto& b3 = rx;    // auto = int
    auto& b4 = crx;   // auto = const int
    
    // auto 万能引用(类似模板 T&&)
    auto&& c1 = x;     // auto = int&
    auto&& c2 = cx;    // auto = const int&
    auto&& c3 = rx;    // auto = int&
    auto&& c4 = crx;   // auto = const int&
    auto&& c5 = 30;    // auto = int (右值引用)
    
    // decltype(auto) 精确推导类型
    decltype(auto) d1 = x;      // int
    decltype(auto) d2 = (x);    // int&(带括号的表达式)
    decltype(auto) d3 = rx;     // int&
    decltype(auto) d4 = crx;    // const int&
    
    return 0;
}

7. 实际应用场景示例

场景1:通用包装器

#include <iostream>
#include <functional>

// 通用函数包装器
template<typename Func, typename... Args>
decltype(auto) call_and_log(Func&& func, Args&&... args) {
    std::cout << "Calling function..." << std::endl;
    
    // 完美转发所有参数
    if constexpr (std::is_same_v<void, 
                   decltype(func(std::forward<Args>(args)...))>) {
        // 返回 void 的函数
        func(std::forward<Args>(args)...);
        std::cout << "Function returned void" << std::endl;
    } else {
        // 有返回值的函数
        auto result = func(std::forward<Args>(args)...);
        std::cout << "Function returned: " << result << std::endl;
        return result;
    }
}

int add(int a, int b) {
    return a + b;
}

void print(const std::string& msg) {
    std::cout << "Message: " << msg << std::endl;
}

int main() {
    auto sum = call_and_log(add, 10, 20);
    call_and_log(print, "Hello, World!");
    
    return 0;
}

场景2:通用工厂函数

#include <iostream>
#include <memory>
#include <utility>

class Widget {
public:
    Widget() { std::cout << "Default constructor\n"; }
    Widget(int x) { std::cout << "Constructor with int: " << x << "\n"; }
    Widget(const std::string& s) { std::cout << "Constructor with string: " << s << "\n"; }
    
    Widget(const Widget&) { std::cout << "Copy constructor\n"; }
    Widget(Widget&&) { std::cout << "Move constructor\n"; }
    
    ~Widget() { std::cout << "Destructor\n"; }
};

// 通用工厂函数
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
    // 完美转发参数到构造函数
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

// 自定义工厂,支持不同构造方式
template<typename T, typename... Args>
T create_object(Args&&... args) {
    // 可能在这里添加日志、验证等
    return T(std::forward<Args>(args)...);
}

int main() {
    std::cout << "=== 创建对象测试 ===\n";
    
    auto w1 = make_unique<Widget>();
    auto w2 = make_unique<Widget>(42);
    auto w3 = make_unique<Widget>("Hello");
    
    Widget w4 = create_object<Widget>();
    Widget w5 = create_object<Widget>(100);
    
    // 转发左值/右值
    Widget temp(200);
    Widget w6 = create_object<Widget>(temp);        // 复制构造
    Widget w7 = create_object<Widget>(std::move(temp)); // 移动构造
    
    return 0;
}

场景3:条件转发

#include <iostream>
#include <type_traits>

// 条件性转发:只在特定条件下转发为右值
template<typename T>
void process_conditionally(T&& param) {
    if constexpr (std::is_integral_v<std::remove_reference_t<T>>) {
        // 对于整数类型,总是按值处理
        int value = param;  // 拷贝
        std::cout << "Integral: " << value << std::endl;
    } else if constexpr (std::is_lvalue_reference_v<T&&>) {
        // 左值:保持为左值
        std::cout << "Lvalue reference" << std::endl;
        other_process(param);  // 按左值传递
    } else {
        // 右值:转发为右值
        std::cout << "Rvalue reference" << std::endl;
        other_process(std::move(param));  // 按右值传递
    }
}

void other_process(int&) {
    std::cout << "Processing lvalue" << std::endl;
}

void other_process(int&&) {
    std::cout << "Processing rvalue" << std::endl;
}

int main() {
    int x = 10;
    const int cx = 20;
    
    process_conditionally(x);   // 左值
    process_conditionally(cx);  // 左值(常量)
    process_conditionally(30);  // 右值
    
    return 0;
}

8. 总结表格:模板引用参数推导规则

参数声明 传递左值 传递常量左值 传递右值 T 推导结果 param 类型
T param 拷贝 拷贝(忽略 const) 拷贝 去掉引用和const T
T& param 引用 常量引用 ❌ 错误 原始类型 T&
const T& param 常量引用 常量引用 常量引用 去掉const const T&
T&& param 左值引用 常量左值引用 右值引用 引用折叠 T&&(折叠后)
const T&& param ❌ 很少用 ❌ 很少用 常量右值引用 去掉const const T&&

9. 最佳实践建议

  1. 优先使用万能引用 + std::forward 进行完美转发
  2. 需要拷贝时使用值传递或 std::remove_reference_t
  3. 只读访问使用 const T&
  4. 修改传入参数使用 T&
  5. 处理数组使用引用传递以保持大小信息
  6. 使用 decltype(auto) 精确控制返回类型

10. 常见陷阱

// 陷阱1:模板参数不是万能引用
template<typename T>
void not_forwarding_ref(const T&& param) {  // ❌ 不是万能引用
    // 只是普通的右值引用
}

// 陷阱2:auto&& 在模板中不是万能引用
template<typename T>
void func(std::vector<T>&& param) {  // ❌ 不是万能引用
    // 只是普通的右值引用
}

// 陷阱3:忘记 std::forward
template<typename T>
void bad_forward(T&& param) {
    other_func(param);  // ❌ 总是按左值传递
    // 应该使用 other_func(std::forward<T>(param));
}

// 陷阱4:在推导上下文中使用 std::move
template<typename T>
void dubious_move(T&& param) {
    other_func(std::move(param));  // ❌ 可能移动了左值
    // 应该检查是否是右值
}

理解模板引用参数的推导规则是掌握现代 C++ 模板编程的关键!


帮我再分析下 C++ 模板,参数为 T&& 的情况 -- to deepseek

C++ 模板参数 T&& 的深度分析

T&& 是 C++ 中最微妙和强大的特性之一,它不总是右值引用。让我详细分析各种情况。

1. 万能引用(Universal Reference) vs 右值引用

关键区别:类型推导

// 情况1:类型推导发生 → T&& 是万能引用
template<typename T>
void func(T&& param) {  // T&& 是万能引用
    // 可以绑定到左值、右值、const等
}

// 情况2:类型已确定 → T&& 是右值引用
template<typename T>
class Widget {
public:
    void process(T&& param);  // ❌ 不是万能引用!T 已确定
    // T&& 是右值引用
};

// 情况3:非模板 → 右值引用
void func(int&& param);  // 普通的右值引用

2. 引用折叠(Reference Collapsing)的魔法

#include <iostream>
#include <type_traits>

template<typename T>
void analyze(T&& param) {
    // 引用折叠规则:
    // T& + && → T&
    // T&& + & → T&  
    // T& + & → T&
    // T&& + && → T&&
    
    std::cout << "Type T: " << typeid(T).name() 
              << ", is lvalue ref: " << std::is_lvalue_reference_v<T>
              << ", is rvalue ref: " << std::is_rvalue_reference_v<T>
              << std::endl;
              
    std::cout << "Type param: " << typeid(param).name()
              << ", is lvalue ref: " << std::is_lvalue_reference_v<decltype(param)>
              << ", is rvalue ref: " << std::is_rvalue_reference_v<decltype(param)>
              << std::endl;
}

int main() {
    int x = 10;
    const int cx = 20;
    int& rx = x;
    const int& crx = x;
    
    std::cout << "=== 万能引用分析 ===\n";
    
    analyze(x);      // T = int&, param = int&
    // 推导过程:func(T&&) 传入 int&
    // T 推导为 int&
    // 参数类型: int& && → 折叠为 int&
    
    analyze(cx);     // T = const int&, param = const int&
    
    analyze(rx);     // T = int&, param = int&
    
    analyze(crx);    // T = const int&, param = const int&
    
    analyze(30);     // T = int, param = int&&
    // 推导过程:func(T&&) 传入 int
    // T 推导为 int
    // 参数类型: int&& → 保持为 int&&
    
    return 0;
}

3. 完美转发(Perfect Forwarding)的实现

#include <iostream>
#include <utility>
#include <type_traits>

// 通用包装器:完美转发所有参数
template<typename Func, typename... Args>
decltype(auto) perfect_forward_wrapper(Func&& func, Args&&... args) {
    std::cout << "Before calling function\n";
    
    // std::forward 的关键作用:
    // 1. 如果 args 是左值,forward 后仍是左值
    // 2. 如果 args 是右值,forward 后变成右值(可以移动)
    
    if constexpr (std::is_same_v<void, 
                   decltype(std::forward<Func>(func)
                           (std::forward<Args>(args)...))>) {
        // 处理返回 void 的函数
        std::forward<Func>(func)(std::forward<Args>(args)...);
        std::cout << "After calling void function\n";
    } else {
        // 处理有返回值的函数
        auto result = std::forward<Func>(func)
                     (std::forward<Args>(args)...);
        std::cout << "After calling function, result = " 
                  << result << "\n";
        return result;
    }
}

void process_lvalue(int& x) {
    std::cout << "Processing lvalue: " << x << "\n";
    x *= 2;
}

void process_rvalue(int&& x) {
    std::cout << "Processing rvalue: " << x << "\n";
}

int add(int a, int b) {
    return a + b;
}

int main() {
    int value = 42;
    
    std::cout << "=== 完美转发测试 ===\n";
    
    // 转发左值引用
    perfect_forward_wrapper(process_lvalue, value);
    std::cout << "Value after processing: " << value << "\n";
    
    // 转发右值
    perfect_forward_wrapper(process_rvalue, 100);
    
    // 转发多个参数
    auto sum = perfect_forward_wrapper(add, 10, 20);
    std::cout << "Sum: " << sum << "\n";
    
    // 转发 lambda
    perfect_forward_wrapper([](int x) { 
        return x * x; 
    }, 5);
    
    return 0;
}

4. std::forward 的实现原理

// 让我们看看 std::forward 的典型实现
namespace my_std {
    // 左值引用版本
    template<typename T>
    constexpr T&& forward(std::remove_reference_t<T>& t) noexcept {
        return static_cast<T&&>(t);  // 引用折叠在这里发生
    }
    
    // 右值引用版本  
    template<typename T>
    constexpr T&& forward(std::remove_reference_t<T>&& t) noexcept {
        static_assert(!std::is_lvalue_reference_v<T>,
                     "Cannot forward rvalue as lvalue");
        return static_cast<T&&>(t);
    }
}

// 实际使用中的转换
template<typename T>
void example(T&& param) {
    // 假设 param 是左值引用
    // T = int&
    // my_std::forward<T>(param) 展开:
    // my_std::forward<int&>(param)
    // 调用 forward(std::remove_reference_t<int&>& t)
    // std::remove_reference_t<int&> = int
    // 所以是 forward(int& t)
    // 返回 static_cast<int& &&>(t) → static_cast<int&>(t)
    // 保持了左值引用
    
    // 假设 param 是右值
    // T = int
    // my_std::forward<int>(param)
    // 调用 forward(int&& t)(右值引用版本)
    // 返回 static_cast<int&&>(t)
    // 转换为右值引用
}

5. 常见陷阱和错误

陷阱1:错误地使用 std::move

template<typename T>
void bad_example(T&& param) {
    // ❌ 危险:可能移动了左值
    some_function(std::move(param));
    
    // ✅ 正确:使用 std::forward
    some_function(std::forward<T>(param));
}

void test() {
    int x = 10;
    bad_example(x);  // ❌ 移动了左值 x!
    // x 现在处于未定义状态
}

陷阱2:多次使用转发后的参数

template<typename T>
void use_twice(T&& param) {
    // ❌ 危险:如果 param 是右值,第一次使用后可能被移动
    process1(std::forward<T>(param));
    process2(std::forward<T>(param));  // 可能使用已移动的对象
    
    // ✅ 解决方案1:如果需要多次使用,先拷贝
    auto copy = param;  // 创建副本
    process1(std::forward<T>(copy));
    process2(std::forward<T>(copy));
    
    // ✅ 解决方案2:针对右值特殊处理
    if constexpr (std::is_rvalue_reference_v<decltype(param)>) {
        // 是右值,只能使用一次
        process_once(std::move(param));
    } else {
        // 是左值,可以多次使用
        process1(param);
        process2(param);
    }
}

陷阱3:auto&& 不是万能引用

template<typename T>
void func(std::vector<T>&& param) {  // ❌ 不是万能引用!
    // 这是普通的右值引用
    // 因为 vector<T> 不是类型推导的 T
    // T 是推导的,但 vector<T> 整体是一个类型
}

// ✅ 正确:真正的万能引用
template<typename T>
void func(T&& param) {  // T 是推导的,T&& 是万能引用
}

6. 实际应用场景

场景1:工厂函数模板

#include <memory>
#include <utility>

// 完美转发工厂函数
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

// 可变参数版本
template<typename T, typename... Args>
T create(Args&&... args) {
    // 可以在这里添加日志、验证等
    return T(std::forward<Args>(args)...);
}

// 使用示例
class Widget {
public:
    Widget(int id, std::string name) 
        : id(id), name(std::move(name)) {}
    
private:
    int id;
    std::string name;
};

int main() {
    // 完美转发构造参数
    auto w1 = make_unique<Widget>(1, "Alice");
    auto w2 = create<Widget>(2, "Bob");
    
    return 0;
}

场景2:通用包装器和装饰器

#include <iostream>
#include <chrono>

// 计时装饰器
template<typename Func, typename... Args>
auto time_function(Func&& func, Args&&... args) {
    auto start = std::chrono::high_resolution_clock::now();
    
    // 完美转发调用
    if constexpr (std::is_same_v<void, 
                   decltype(std::forward<Func>(func)
                           (std::forward<Args>(args)...))>) {
        std::forward<Func>(func)(std::forward<Args>(args)...);
        auto end = std::chrono::high_resolution_clock::now();
        return std::chrono::duration<double>(end - start).count();
    } else {
        auto result = std::forward<Func>(func)
                     (std::forward<Args>(args)...);
        auto end = std::chrono::high_resolution_clock::now();
        return std::pair{result, 
                        std::chrono::duration<double>(end - start).count()};
    }
}

// 使用示例
int expensive_computation(int n) {
    int sum = 0;
    for (int i = 0; i < n; ++i) {
        sum += i * i;
    }
    return sum;
}

int main() {
    // 计时任意函数
    auto [result, time] = time_function(expensive_computation, 1000000);
    std::cout << "Result: " << result << ", Time: " << time << "s\n";
    
    return 0;
}

场景3:链式调用构建器

#include <iostream>
#include <string>
#include <vector>

// 链式构建器模式
template<typename T>
class Builder {
    T value;
    
public:
    template<typename U>
    Builder(U&& init_value) 
        : value(std::forward<U>(init_value)) {}
    
    template<typename Func>
    auto transform(Func&& func) && {  // 右值引用限定
        // 注意:this 是右值,可以移动 value
        return Builder<decltype(func(std::move(value)))>(
            std::forward<Func>(func)(std::move(value)));
    }
    
    template<typename Func>
    auto transform(Func&& func) & {  // 左值引用限定
        // this 是左值,不能移动
        return Builder<decltype(func(value))>(
            std::forward<Func>(func)(value));
    }
    
    T&& build() && {  // 只能从右值构建
        return std::move(value);
    }
    
    const T& build() & {  // 从左值返回引用
        return value;
    }
};

int main() {
    std::string str = "Hello";
    
    // 从左值开始
    Builder<std::string> builder(str);
    auto result = builder
        .transform([](std::string s) { 
            return s + " World"; 
        })
        .transform([](std::string s) {
            return s.length();
        })
        .build();
    
    std::cout << "Result: " << result << "\n";
    
    // 从右值开始
    auto result2 = Builder<std::string>("Hello")
        .transform([](std::string s) { 
            return std::move(s) + " World";  // 可以移动
        })
        .build();  // 返回右值
    
    return 0;
}

7. SFINAE 和约束(C++20)

#include <type_traits>
#include <concepts>

// 使用 SFINAE 约束 T&& 参数
template<typename T>
auto process_impl(T&& param) -> std::enable_if_t<
    std::is_integral_v<std::remove_reference_t<T>>, 
    void
> {
    std::cout << "Processing integral type\n";
}

template<typename T>
auto process_impl(T&& param) -> std::enable_if_t<
    std::is_floating_point_v<std::remove_reference_t<T>>,
    void
> {
    std::cout << "Processing floating point type\n";
}

// C++20 概念约束
template<typename T>
concept Numeric = std::is_arithmetic_v<std::remove_reference_t<T>>;

template<typename T>
requires Numeric<T>
void process_concept(T&& param) {
    if constexpr (std::is_integral_v<std::remove_reference_t<T>>) {
        std::cout << "Integral: " << param << "\n";
    } else {
        std::cout << "Floating: " << param << "\n";
    }
}

// 约束转发引用
template<typename T>
requires std::is_constructible_v<std::string, T>
std::string make_string(T&& value) {
    return std::string(std::forward<T>(value));
}

8. 性能分析和优化

#include <vector>
#include <chrono>

// 对比不同参数传递方式的性能
class Data {
    std::vector<int> buffer;
public:
    Data(size_t size) : buffer(size, 1) {}
    
    // 各种参数传递版本
    Data(const Data& other) : buffer(other.buffer) {
        std::cout << "Copy constructor\n";
    }
    
    Data(Data&& other) noexcept : buffer(std::move(other.buffer)) {
        std::cout << "Move constructor\n";
    }
};

// 版本1:按值传递(可能产生拷贝)
template<typename T>
void process_by_value(T data) {
    // 总是产生拷贝或移动
}

// 版本2:const 引用(只读)
template<typename T>
void process_by_const_ref(const T& data) {
    // 只读访问,无拷贝
}

// 版本3:万能引用(最优转发)
template<typename T>
void process_by_forwarding_ref(T&& data) {
    // 完美转发:左值无拷贝,右值可移动
    Data local_data = std::forward<T>(data);
    // 根据 data 的值类别决定使用拷贝还是移动
}

void performance_test() {
    Data data(1000000);
    
    auto test = [&](auto&& func, auto&&... args) {
        auto start = std::chrono::high_resolution_clock::now();
        for (int i = 0; i < 100; ++i) {
            func(std::forward<decltype(args)>(args)...);
        }
        auto end = std::chrono::high_resolution_clock::now();
        return std::chrono::duration<double>(end - start).count();
    };
    
    std::cout << "By value: " 
              << test(process_by_value<Data>, data) << "s\n";
    
    std::cout << "By const ref: " 
              << test(process_by_const_ref<Data>, data) << "s\n";
    
    std::cout << "By forwarding ref (lvalue): " 
              << test(process_by_forwarding_ref<Data&>, data) << "s\n";
    
    std::cout << "By forwarding ref (rvalue): " 
              << test(process_by_forwarding_ref<Data>, std::move(data)) << "s\n";
}

9. 编译期类型检查工具

#include <iostream>
#include <type_traits>

// 编译期类型检查工具
template<typename T>
void check_forwarding_reference(T&& param) {
    std::cout << "\n=== Type Analysis ===\n";
    std::cout << "Original T: " << typeid(T).name() << "\n";
    std::cout << "T is lvalue ref: " 
              << std::is_lvalue_reference_v<T> << "\n";
    std::cout << "T is rvalue ref: " 
              << std::is_rvalue_reference_v<T> << "\n";
    
    using ParamType = decltype(param);
    std::cout << "Param type: " << typeid(ParamType).name() << "\n";
    std::cout << "Param is lvalue ref: " 
              << std::is_lvalue_reference_v<ParamType> << "\n";
    std::cout << "Param is rvalue ref: " 
              << std::is_rvalue_reference_v<ParamType> << "\n";
    
    using DecayedType = std::decay_t<T>;
    std::cout << "Decayed T: " << typeid(DecayedType).name() << "\n";
}

// 宏工具帮助调试
#define CHECK_FORWARDING(type, value) \
    std::cout << "\n--- Testing: " #value " ---\n"; \
    check_forwarding_reference<type>(value)

int main() {
    int x = 10;
    const int cx = 20;
    int& rx = x;
    const int& crx = x;
    
    CHECK_FORWARDING(decltype(x)&, x);      // 左值引用
    CHECK_FORWARDING(decltype(cx)&, cx);    // const 左值引用
    CHECK_FORWARDING(int, 30);              // 右值
    
    return 0;
}

10. 总结表格:T&& 的行为规则

场景 T 的推导 参数类型(引用折叠后) 值类别
func(lvalue) T& T& 左值
func(const lvalue) const T& const T& 左值
func(rvalue) T T&& 右值
func(const rvalue) const T const T&& 右值
func(lvalue_ref) T& T& 左值
func(const_lvalue_ref) const T& const T& 左值

11. 黄金法则

  1. T&& 在类型推导时是万能引用,否则是右值引用
  2. 总是使用 std::forward<T> 转发万能引用参数
  3. 避免在万能引用上使用 std::move(除非确定需要移动)
  4. std::forward 是有条件的 std::move,根据类型决定
  5. 引用折叠是 T&& 工作的核心机制
  6. auto&& 也是万能引用,遵循相同规则
  7. 完美转发可能影响异常安全性,需要谨慎

12. 现代 C++ 最佳实践

// C++17:if constexpr 简化完美转发
template<typename T>
void modern_process(T&& value) {
    if constexpr (std::is_same_v<std::remove_cvref_t<T>, int>) {
        // 处理 int 类型
        std::cout << "int: " << value << "\n";
    } else if constexpr (std::is_same_v<std::remove_cvref_t<T>, std::string>) {
        // 处理 string 类型
        std::cout << "string: " << std::forward<T>(value) << "\n";
    }
}

// C++20:概念约束
template<typename T>
concept Printable = requires(T t) {
    { std::cout << t } -> std::same_as<std::ostream&>;
};

template<Printable T>
void print_forward(T&& value) {
    std::cout << std::forward<T>(value) << "\n";
}

掌握 T&& 的微妙之处是成为 C++ 专家的关键一步。它提供了无与伦比的灵活性和性能,但也需要对其工作原理有深入的理解。