万能引用是让函数同时接受左值(变量原始类型,引用)和右值(临时变量,std::move 返回值)作为引用形式的参数的一种方法。
这是一段来自 MLIR 项目的源代码,用于遍历 IR 对其执行操作:
template <WalkOrder Order = WalkOrder::PostOrder,typename Iterator = ForwardIterator, typename FnT,typename RetT = detail::walkResultType<FnT>>
std::enable_if_t<llvm::function_traits<std::decay_t<FnT>>::num_args == 1,RetT>
walk(FnT &&callback) {return detail::walk<Order, Iterator>(this, std::forward<FnT>(callback));
}
该函数接受四个模板参数,分别是:
-
Order,非类型模板参数(NTTP),通过传入枚举类WalkOrder控制函数行为 -
Iterator,控制遍历时从第一个访问到最后一个子节点(Iterator),还是反之(ReverseIterator) -
FnT,执行实际操作的可调用对象(Callable),可以是普通函数,函数指针,函数左/右值引用,Lambda 表达式,Funtor(重载了操作符()的类或结构体),std::bind绑定表达式,std::function<R(Args...)>类型擦除包装器 -
RetT,传入的函数的返回类型
上述代码中通过使用 std::forward<FnT>(callback) 通过 FnT 保留的函数原始类型,实现对参数的无损转发。
walk(FnT &&callback) 这里就是万能引用,无论传入的参数是什么类型都可以转化成引用形式:
-
实参:X 类型左值表达式(具名变量
X x、右值引用变量名rr等一切左值)推导规则:万能引用特殊推导 →
FnT = X&
引用折叠:FnT&& = X& && = X&
示例:int x; walk(x); // x 是int左值表达式 int&& rr = std::move(x); walk(rr); // rr 变量类型int&&,但表达式rr是左值,同样走本条 -
实参:X 类型右值表达式(字面量、临时对象、
std::move(变量))推导规则:
FnT = X(裸类型,不带引用)
引用折叠:FnT&& = X && = X&&
示例:walk(10); // 字面量纯右值 walk(std::move(x)); // move生成亡值(右值) walk(std::move(rr)); walk(MyOp{}); // 临时对象纯右值