You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将C++万能引用限制为const T&或T&&类型?

能否让万能引用仅接受const左值引用或右值引用,拒绝普通左值引用?

可以通过模板约束实现这个需求,先看原问题场景:

原问题代码示例

#include <string>
#include <iostream>

struct S {
    S() {}
    S(const S&) {
        std::cout << "copied" << std::endl;
    }
    S(S&&) {
        std::cout << "moved" << std::endl;
    }    
};

auto foo(auto&& arg) {
    return std::move(arg);
}

int main() {
    std::cout << "temp call" << std::endl;
    foo(S());
    std::cout << std::endl << "variable call" << std::endl;
    S s;
    foo(s);
    std::cout << std::endl << "move call" << std::endl;
    foo(std::move(s));
}

原输出结果

temp call
moved

variable call
moved            <--- 此处期望触发拷贝构造(copied)

move call
moved

用户已知正确处理万能引用需使用std::forward:

auto foo(auto&& arg) {
    return std::forward<decltype(arg)>(arg);
}

但希望直接在函数签名层面约束参数只能是const T&或T&&,拒绝普通左值引用T&。


解决方案

方法1:C++20 requires表达式

利用C++20的约束表达式直接在签名中限制参数类型:

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

struct S {
    S() {}
    S(const S&) {
        std::cout << "copied" << std::endl;
    }
    S(S&&) {
        std::cout << "moved" << std::endl;
    }    
};

auto foo(auto&& arg) requires 
    (std::is_const_v<std::remove_reference_t<decltype(arg)>> && std::is_lvalue_reference_v<decltype(arg)>) || 
    std::is_rvalue_reference_v<decltype(arg)>
{
    return std::forward<decltype(arg)>(arg);
}

int main() {
    std::cout << "temp call" << std::endl;
    foo(S()); // 正常调用,匹配右值引用,输出moved
    std::cout << std::endl << "const变量调用" << std::endl;
    const S cs;
    foo(cs); // 正常调用,匹配const左值引用,输出copied
    std::cout << std::endl << "move调用" << std::endl;
    S s;
    foo(std::move(s)); // 正常调用,匹配右值引用,输出moved
    
    // S s2;
    // foo(s2); // 编译错误:不满足约束,普通左值引用被拒绝
}

方法2:SFINAE(C++11及以上兼容)

针对C++20之前的版本,使用std::enable_if实现约束:

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

struct S {
    S() {}
    S(const S&) {
        std::cout << "copied" << std::endl;
    }
    S(S&&) {
        std::cout << "moved" << std::endl;
    }    
};

template<typename T, typename = std::enable_if_t<
    (std::is_const_v<std::remove_reference_t<T>> && std::is_lvalue_reference_v<T>) || 
    std::is_rvalue_reference_v<T>
>>
auto foo(T&& arg) {
    return std::forward<T>(arg);
}

int main() {
    std::cout << "temp call" << std::endl;
    foo(S()); // 正常调用
    std::cout << std::endl << "const变量调用" << std::endl;
    const S cs;
    foo(cs); // 正常调用
    std::cout << std::endl << "move调用" << std::endl;
    S s;
    foo(std::move(s)); // 正常调用
    
    // S s2;
    // foo(s2); // 编译错误:模板推导失败
}

约束原理

  • 对于const T&:std::remove_reference_t<T>是const T(is_const_v为true),且是左值引用(is_lvalue_reference_v为true),满足第一个条件。
  • 对于T&&:is_rvalue_reference_v<T>为true,满足第二个条件。
  • 对于普通左值引用T&:两个条件都不满足,编译时直接报错,拒绝此类调用。

内容的提问来源于stack exchange,提问作者user3612643

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:40:57