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()处执行.
浙公网安备 33010602011771号