C++推导本
参考
大家知道,成员函数
都有隐式
对象参数,对非静态
成员函数,它就是this
指针;
struct S_implicit {
void foo() {}
};
struct S_explicit {
void foo(this S_explicit&) {}//显式写出来.
};
1:消除修饰
带来的冗余
,示例:
//之前
struct S_implicit {
int data_;
int& foo() & { return data_; }
const int& foo() const& { return data_; }
};
// 之后.
struct S_explicit {
int data_;
template <class Self>
auto&& foo(this Self& self) {
return std::forward<Self>(self).data_;
}//转发数据了.
};
消除了&,const&,&&,const&&
等逻辑.借助推导本
,只需编写一个版本
即可.
这里使用了模板形式
参数,一般,建议按显式对象
参数名使用Self
.
借助推导本
,可实现递归λ
.
int main() {
auto gcd = [](this auto self, int a, int b) -> int {
return b == 0 ? a : self(b, a % b);
};
std::cout << gcd(20, 30) << "\n";
}
这可再次增强λ
函数.比如,借助推导本
,可简化CRTP
.
//之前
// CRTP
template <class Derived>
struct Base {
void foo() {
auto& self = *static_cast<Derived*>(this);
self.bar();
}
};
struct Derived : Base<Derived> {
void bar() const {
std::cout << "CRTP Derived\n";
}
};
之后,推导本
struct Base {
template <class Self>
void foo(this Self& self) {
self.bar();
}
};
struct Derived : Base {
void bar() const {
std::cout << "Deducing this Derived\n";
}
};
该新实现CRTP
,可省去CR
,甚至是T
,要更加自然,更加清晰.新定制点示例:
namespace mylib {
struct S {
auto abstract_interface(this auto& self, int param) {
self.concrete_algo1(self.concrete_algo2(param));
}
};
} // mylib空间
namespace userspace {
struct M : mylib::S {
auto concrete_algo1(int val) {}
auto concrete_algo2(int val) const {
return val * 6;
}
};
} //
int main() {
using userspace::M;
M m;
m.abstract_interface(4);
}
这样,依然是静态多态
,但代码
更加清晰,无侵入
,并支持显式可选
,值得使用.
定制点
,这里
推导本
还可用来解决根据闭包
类型的完美转发λ
抓参数的问题.
亦即,如果λ
函数的类型为左值
,那么抓的参数就以左值
转发;如果为右值
,那么就以右值
转发.示例:
#include <iostream>
#include <type_traits>
#include <utility> // for std::forward_like
auto get_message() {
return 42;
}
struct Scheduler {
auto submit(auto&& m) {
std::cout << std::boolalpha;
std::cout << std::is_lvalue_reference<decltype(m)>::value << "\n";
std::cout << std::is_rvalue_reference<decltype(m)>::value << "\n";
return m;
}
};
int main() {
Scheduler scheduler;
auto callback = [m=get_message(), &scheduler](this auto&& self) -> bool {
return scheduler.submit(std::forward_like<decltype(self)>(m));
};
callback(); // retry(callback)
std::move(callback)(); // try-or-fail(rvalue)
}
// Output:
// true
// false
// false
// true
若是没有推导本
,则无法简单完成该操作.
另一个是可按值
形式传递this
,对小对象
,可提高
性能.示例:
struct S {
int data_;
int foo(); // 隐式
// int foo(this S); // 按值传递
};
int main() {
S s{42};
return s.foo();
}
// 隐式`本`生成的汇编代码:
// sub rsp, 40 ;00000028H
// lea rcx, QWORD PTR s$[rsp]
// mov DWORD PTR s$[rsp], 42 ;0000002aH
// call int S::foo(void) ;S::foo
// add rsp, 40 ;00000028H
// ret 0
// 按值传递生成的汇编代码:
// mov ecx, 42 ; 0000002aH
// jmp static int S::foo(this S); S::foo
对隐式this
指针,生成汇编代码
需要先分配
栈空间,保存this
指针到rcx
寄存器中,再赋值42
到data_
中,然后调用foo()
,最后平栈.
而按值传递this
,则无需
那些操作,因为值传递的this
不会影响s变量,可优化掉
中间步骤,不再需要分配和平栈
操作,所以可直接保存42
到寄存器,再jmp
到foo()
处执行.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现