如何通过C++ traits判断函数参数是否为调用处的匿名临时对象?
用C++ Traits判断函数参数是否为匿名临时对象
完全可以实现。核心思路是利用C++的值类别特性:匿名临时对象属于纯右值(prvalue),而具名对象、左值引用、通过std::move转换的将亡值(xvalue)都不属于这类。我们可以通过函数重载优先级和traits模板来捕获这个差异。
实现方案
1. 定义is_anonymous_temporary Trait
这个trait通过重载辅助函数,区分纯右值和其他值类别:
#include <type_traits> template <typename T> struct is_anonymous_temporary { private: // 匹配左值和将亡值 template <typename U> static std::false_type test(U&); template <typename U> static std::false_type test(std::remove_reference_t<U>&&); // 匹配纯右值(匿名临时对象) template <typename U> static std::true_type test(U&&); public: static constexpr bool value = decltype(test(std::declval<T>()))::value; }; // 简化使用的别名 template <typename T> constexpr bool is_anonymous_temporary_v = is_anonymous_temporary<T>::value;
2. 在函数中判断实参类型
结合完美转发,我们可以在函数内部准确判断传入的是否是匿名临时对象:
#include <iostream> template <typename T> void process(T&& arg) { // 通过std::forward保留实参的值类别,判断是否为纯右值 if constexpr (is_anonymous_temporary_v<std::remove_cvref_t<T>> && std::is_prvalue_v<decltype(std::forward<T>(arg))>) { std::cout << "传入的是匿名临时对象\n"; } else { std::cout << "传入的不是匿名临时对象\n"; } } int main() { int x = 42; process(x); // 左值:输出"传入的不是匿名临时对象" process(42); // 匿名临时对象:输出"传入的是匿名临时对象" process(std::move(x)); // 将亡值:输出"传入的不是匿名临时对象" process(std::string("test")); // 匿名临时对象:输出"传入的是匿名临时对象" }
原理说明
- 辅助函数
test的重载优先级:当传入纯右值时,test(U&&)会被优先匹配,返回std::true_type;左值匹配test(U&),将亡值匹配test(std::remove_reference_t<U>&&),两者都返回std::false_type。 std::declval<T>用于在编译期模拟获取T类型的表达式,通过decltype推导test函数的返回类型,从而确定is_anonymous_temporary<T>::value的值。- 在
process函数中,std::forward<T>(arg)保留了实参原始的值类别,结合std::is_prvalue_v可以进一步确保我们判断的是纯右值(即匿名临时对象)。
注意事项
- 如果你的场景不需要区分将亡值和纯右值,可以简化判断逻辑,只使用
is_anonymous_temporary_v。 - 该方案适用于C++17及以上标准(用到了
constexpr if和std::is_prvalue_v),如果需要兼容更早标准,可以替换为标签分发等方式。
内容的提问来源于stack exchange,提问作者P45 Imminent
相关产品推荐
相关产品推荐

