Proxy 库解析(四)
前言
本来说 Proxy 是个 C++20 的头文件库,结果我本地的 GCC12 又编译不过去,逼得我花了两个多小时把整套工具链都升了一遍
顺手换了个 clangd,This is true LSP! 并非,看起来好像也没比 intelligence 多强,加上编译器还是 GCC 于是又换回去了
回到正题,本文受到这个的启发,我顺了一遍基本上是一样的,只是有些代码的名字或者位置变了
可以结合本文的结果,更好的理解中间发生了什么
其最新的提案,写的很清楚,也建议看一看,理一理思路,提案
但是读完了还是觉得,别的都不错,强制写 12 个 accessor 重载还是太蠢了,用宏来解决就更蠢了
中间结果
让 claude code 写了个输出中间结果和类型的代码如下,试着玩一玩可能会有想不到的发现
点击查看代码
#include "proxy/v4/proxy.h"
#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <type_traits>
#include <string>
#include <sstream>
#include <memory>
#include <cxxabi.h>
#include <concepts>
// Utility to demangle type names
std::string demangle(const char* name) {
int status;
char* demangled = abi::__cxa_demangle(name, nullptr, nullptr, &status);
if (status == 0) {
std::string result(demangled);
free(demangled);
return result;
}
return name;
}
// Helper to convert constraint_level enum to string
const char* constraint_level_to_string(pro::constraint_level level) {
switch (level) {
case pro::constraint_level::none: return "none";
case pro::constraint_level::nontrivial: return "nontrivial";
case pro::constraint_level::nothrow: return "nothrow";
case pro::constraint_level::trivial: return "trivial";
default: return "unknown";
}
}
// Helper to convert bool to string
const char* bool_to_string(bool value) {
return value ? "true" : "false";
}
// === Trait to strip function qualifiers and record info ===
template<typename T>
struct function_traits_ex {
using base_type = T; // fallback, for non-function types
static constexpr int ref_qual = 0; // 0=none, 1=&, 2=&&
static constexpr bool is_noexcept = false;
static constexpr bool is_const = false;
};
// Plain function
template<typename R, typename... Args>
struct function_traits_ex<R(Args...)> {
using base_type = R(Args...); // naked function type
static constexpr int ref_qual = 0;
static constexpr bool is_noexcept = false;
static constexpr bool is_const = false;
};
template<typename R, typename... Args>
struct function_traits_ex<R(Args...) noexcept> {
using base_type = R(Args...); // strip noexcept
static constexpr int ref_qual = 0;
static constexpr bool is_noexcept = true;
static constexpr bool is_const = false;
};
// const-qualified
template<typename R, typename... Args>
struct function_traits_ex<R(Args...) const> {
using base_type = R(Args...);
static constexpr int ref_qual = 0;
static constexpr bool is_noexcept = false;
static constexpr bool is_const = true;
};
template<typename R, typename... Args>
struct function_traits_ex<R(Args...) const noexcept> {
using base_type = R(Args...);
static constexpr int ref_qual = 0;
static constexpr bool is_noexcept = true;
static constexpr bool is_const = true;
};
// & qualified
template<typename R, typename... Args>
struct function_traits_ex<R(Args...) &> {
using base_type = R(Args...);
static constexpr int ref_qual = 1;
static constexpr bool is_noexcept = false;
static constexpr bool is_const = false;
};
template<typename R, typename... Args>
struct function_traits_ex<R(Args...) & noexcept> {
using base_type = R(Args...);
static constexpr int ref_qual = 1;
static constexpr bool is_noexcept = true;
static constexpr bool is_const = false;
};
template<typename R, typename... Args>
struct function_traits_ex<R(Args...) const &> {
using base_type = R(Args...);
static constexpr int ref_qual = 1;
static constexpr bool is_noexcept = false;
static constexpr bool is_const = true;
};
template<typename R, typename... Args>
struct function_traits_ex<R(Args...) const & noexcept> {
using base_type = R(Args...);
static constexpr int ref_qual = 1;
static constexpr bool is_noexcept = true;
static constexpr bool is_const = true;
};
// && qualified
template<typename R, typename... Args>
struct function_traits_ex<R(Args...) &&> {
using base_type = R(Args...);
static constexpr int ref_qual = 2;
static constexpr bool is_noexcept = false;
static constexpr bool is_const = false;
};
template<typename R, typename... Args>
struct function_traits_ex<R(Args...) && noexcept> {
using base_type = R(Args...);
static constexpr int ref_qual = 2;
static constexpr bool is_noexcept = true;
static constexpr bool is_const = false;
};
template<typename R, typename... Args>
struct function_traits_ex<R(Args...) const &&> {
using base_type = R(Args...);
static constexpr int ref_qual = 2;
static constexpr bool is_noexcept = false;
static constexpr bool is_const = true;
};
template<typename R, typename... Args>
struct function_traits_ex<R(Args...) const && noexcept> {
using base_type = R(Args...);
static constexpr int ref_qual = 2;
static constexpr bool is_noexcept = true;
static constexpr bool is_const = true;
};
// === Updated print_type_info ===
template<typename T>
void print_type_info(const std::string& label) {
using traits = function_traits_ex<T>;
using Stripped = typename traits::base_type;
// Always use the stripped base type for typeid
std::cout << label << ": " << demangle(typeid(Stripped).name());
// Append qualifiers
if constexpr (traits::ref_qual == 1) std::cout << " &";
if constexpr (traits::ref_qual == 2) std::cout << " &&";
if constexpr (traits::is_noexcept) std::cout << " noexcept";
if constexpr (traits::is_const) std::cout << " const";
std::cout << std::endl;
// Trait checks should not apply to function types directly
/* if constexpr (std::is_void_v<std::remove_cvref_t<T>>) {
std::cout << " Size: N/A (void type)" << std::endl;
std::cout << " Alignment: N/A (void type)" << std::endl;
std::cout << " Trivially copyable: N/A" << std::endl;
} else if constexpr (std::is_function_v<Stripped>) {
std::cout << " Size: N/A (function type)" << std::endl;
std::cout << " Alignment: N/A (function type)" << std::endl;
std::cout << " Trivially copyable: N/A" << std::endl;
} else {
std::cout << " Size: " << sizeof(Stripped) << " bytes" << std::endl;
std::cout << " Alignment: " << alignof(Stripped) << " bytes" << std::endl;
std::cout << " Trivially copyable: "
<< bool_to_string(std::is_trivially_copyable_v<Stripped>) << std::endl;
std::cout << " Trivially destructible: "
<< bool_to_string(std::is_trivially_destructible_v<Stripped>) << std::endl;
std::cout << " Trivially move constructible: "
<< bool_to_string(std::is_trivially_move_constructible_v<Stripped>) << std::endl;
std::cout << " Copy constructible: "
<< bool_to_string(std::is_copy_constructible_v<Stripped>) << std::endl;
std::cout << " Nothrow copy constructible: "
<< bool_to_string(std::is_nothrow_copy_constructible_v<Stripped>) << std::endl;
std::cout << " Nothrow move constructible: "
<< bool_to_string(std::is_nothrow_move_constructible_v<Stripped>) << std::endl;
} */
}
// Helper to extract tuple elements
template<typename Tuple, std::size_t... Is>
void print_tuple_elements_impl(std::index_sequence<Is...>, const std::string& prefix) {
((print_type_info<std::tuple_element_t<Is, Tuple>>(
prefix + "[" + std::to_string(Is) + "]")), ...);
}
template<typename Tuple>
void print_tuple_elements(const std::string& label) {
constexpr auto size = std::tuple_size_v<Tuple>;
std::cout << label << " (size: " << size << "):" << std::endl;
if constexpr (size > 0) {
print_tuple_elements_impl<Tuple>(std::make_index_sequence<size>{}, " Element");
}
}
// Facade introspection
template<pro::facade F>
struct facade_inspector {
using facade_type = F;
using convention_types = typename F::convention_types;
using reflection_types = typename F::reflection_types;
static void inspect_facade() {
std::cout << "\n=== FACADE INSPECTION ===" << std::endl;
print_type_info<F>("Facade Type");
std::cout << "\nFacade Configuration:" << std::endl;
std::cout << " max_size: " << F::max_size << " bytes" << std::endl;
std::cout << " max_align: " << F::max_align << " bytes" << std::endl;
std::cout << " copyability: " << constraint_level_to_string(F::copyability) << std::endl;
std::cout << " relocatability: " << constraint_level_to_string(F::relocatability) << std::endl;
std::cout << " destructibility: " << constraint_level_to_string(F::destructibility) << std::endl;
print_tuple_elements<convention_types>("Convention Types");
print_tuple_elements<reflection_types>("Reflection Types");
}
};
// Proxy internal structure introspection
template<pro::facade F>
struct proxy_internal_inspector {
private:
// Access private members through friendship exploitation
static const auto& get_meta_unsafe(const pro::proxy<F>& p) {
return pro::details::proxy_helper::get_meta(p);
}
template<typename P>
static auto get_ptr_unsafe(const pro::proxy<F>& p) {
return pro::details::proxy_helper::get_ptr<P, F, pro::details::qualifier_type::const_lv>(p);
}
public:
using facade_traits = pro::details::facade_traits<F>;
using meta_type = typename facade_traits::meta;
using indirect_accessor = typename facade_traits::indirect_accessor;
using direct_accessor = typename facade_traits::direct_accessor;
static void inspect_proxy_structure() {
std::cout << "\n=== PROXY INTERNAL STRUCTURE ===" << std::endl;
print_type_info<pro::proxy<F>>("Proxy Type");
print_type_info<meta_type>("Meta Type");
print_type_info<indirect_accessor>("Indirect Accessor");
print_type_info<direct_accessor>("Direct Accessor");
// Meta pointer inspection
using meta_ptr_type = pro::details::meta_ptr<meta_type>;
print_type_info<meta_ptr_type>("Meta Pointer Type");
std::cout << "\nStorage Details:" << std::endl;
std::cout << " Storage size: " << F::max_size << " bytes" << std::endl;
std::cout << " Storage alignment: " << F::max_align << " bytes" << std::endl;
std::cout << " Actual proxy size: " << sizeof(pro::proxy<F>) << " bytes" << std::endl;
// Check if meta is stored inline or indirectly
if constexpr (sizeof(meta_type) <= sizeof(pro::details::ptr_prototype) &&
alignof(meta_type) <= alignof(pro::details::ptr_prototype) &&
std::is_nothrow_default_constructible_v<meta_type> &&
std::is_trivially_copyable_v<meta_type>) {
std::cout << " Meta storage: INLINE (direct)" << std::endl;
} else {
std::cout << " Meta storage: INDIRECT (pointer)" << std::endl;
}
}
template<typename T>
static void inspect_concrete_instance(const pro::proxy<F>& p) {
std::cout << "\n=== CONCRETE INSTANCE INSPECTION ===" << std::endl;
if (!p.has_value()) {
std::cout << "Proxy is empty!" << std::endl;
return;
}
print_type_info<T>("Stored Concrete Type");
// Get the meta object
const auto& meta = get_meta_unsafe(p);
std::cout << "Meta object address: " << &meta << std::endl;
// Try to access the stored object (this is very unsafe!)
try {
const T& stored_obj = get_ptr_unsafe<T>(p);
std::cout << "Stored object address: " << &stored_obj << std::endl;
std::cout << "Successfully accessed stored object!" << std::endl;
} catch (...) {
std::cout << "Failed to access stored object (type mismatch?)" << std::endl;
}
}
// Extract dispatcher information (very advanced)
template<bool IsDirect, typename D, typename O>
static void inspect_dispatcher() {
using invocation_meta = pro::details::invocation_meta<F, IsDirect, D, O>;
using overload_traits = pro::details::overload_traits<O>;
std::cout << "\n=== DISPATCHER INSPECTION ===" << std::endl;
std::cout << "Is Direct: " << bool_to_string(IsDirect) << std::endl;
print_type_info<D>("Dispatch Type");
print_type_info<O>("Overload Type");
print_type_info<invocation_meta>("Invocation Meta");
print_type_info<typename overload_traits::return_type>("Return Type");
std::cout << "Qualifier: ";
switch (overload_traits::qualifier) {
case pro::details::qualifier_type::lv: std::cout << "lvalue&"; break;
case pro::details::qualifier_type::const_lv: std::cout << "const lvalue&"; break;
case pro::details::qualifier_type::rv: std::cout << "rvalue&&"; break;
case pro::details::qualifier_type::const_rv: std::cout << "const rvalue&&"; break;
}
std::cout << std::endl;
// Additional dispatcher analysis
using dispatcher_type = typename overload_traits::template dispatcher_type<F>;
print_type_info<dispatcher_type>("Dispatcher Function Type");
std::cout << "Dispatcher function pointer size: " << sizeof(dispatcher_type) << " bytes" << std::endl;
}
};
// Enhanced convention introspection with overload analysis
template<typename Conv, pro::facade F>
struct convention_inspector {
static void inspect() {
std::cout << "\n=== CONVENTION INSPECTION ===" << std::endl;
print_type_info<Conv>("Convention Type");
if constexpr (requires { Conv::is_direct; }) {
std::cout << " Is Direct: " << bool_to_string(Conv::is_direct) << std::endl;
}
if constexpr (requires { typename Conv::dispatch_type; }) {
print_type_info<typename Conv::dispatch_type>("Dispatch Type");
}
if constexpr (requires { typename Conv::overload_types; }) {
using overloads = typename Conv::overload_types;
print_tuple_elements<overloads>("Overload Types");
// Show how many overloads this dispatcher handles
constexpr auto num_overloads = std::tuple_size_v<overloads>;
std::cout << "\nThis dispatcher handles " << num_overloads << " overload(s):" << std::endl;
// Analyze each overload individually
analyze_overloads<overloads>(std::make_index_sequence<num_overloads>{});
}
}
private:
template<typename Overloads, std::size_t... Is>
static void analyze_overloads(std::index_sequence<Is...>) {
((analyze_single_overload<std::tuple_element_t<Is, Overloads>>(Is)), ...);
}
template<typename Overload>
static void analyze_single_overload(std::size_t index) {
std::cout << "\n --- Overload " << index << " Analysis ---" << std::endl;
if constexpr (pro::details::overload_traits<Overload>::applicable) {
using traits = pro::details::overload_traits<Overload>;
print_type_info<Overload>(" Signature: ");
print_type_info<typename traits::return_type>(" Return type: ");
std::cout << " Qualifier: ";
switch (traits::qualifier) {
case pro::details::qualifier_type::lv:
std::cout << "lvalue reference (&)"; break;
case pro::details::qualifier_type::const_lv:
std::cout << "const lvalue reference (const &)"; break;
case pro::details::qualifier_type::rv:
std::cout << "rvalue reference (&&)"; break;
case pro::details::qualifier_type::const_rv:
std::cout << "const rvalue reference (const &&)"; break;
}
std::cout << std::endl;
// Show dispatcher function type
using dispatcher_type = typename traits::template dispatcher_type<F>;
print_type_info<dispatcher_type>(" Dispatcher function type: ");
std::cout << " Dispatcher size: " << sizeof(dispatcher_type) << " bytes" << std::endl;
} else {
std::cout << " Invalid overload signature!" << std::endl;
}
}
};
// Memory layout inspector
template<pro::facade F>
void inspect_memory_layout(const pro::proxy<F>& p) {
std::cout << "\n=== MEMORY LAYOUT INSPECTION ===" << std::endl;
const unsigned char* proxy_start = reinterpret_cast<const unsigned char*>(&p);
std::cout << "Proxy object starts at: " << static_cast<const void*>(proxy_start) << std::endl;
std::cout << "Proxy object size: " << sizeof(p) << " bytes" << std::endl;
std::cout << "Has value: " << bool_to_string(p.has_value()) << std::endl;
std::cout << "\n--- Raw Memory Dump ---" << std::endl;
size_t dump_size = sizeof(p);
// Header
std::cout << "Offset ";
for (int i = 0; i < 16; ++i) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << i << " ";
}
std::cout << " ASCII" << std::endl;
std::cout << std::string(8 + 16*3 + 6, '-') << std::endl;
for (size_t i = 0; i < dump_size; i += 16) {
// Print offset
std::cout << std::hex << std::setfill('0') << std::setw(4) << i << ": ";
// Print hex bytes
size_t line_end = std::min(i + 16, dump_size);
for (size_t j = i; j < line_end; ++j) {
std::cout << std::hex << std::setfill('0') << std::setw(2)
<< static_cast<unsigned>(proxy_start[j]) << " ";
}
// Pad remaining space if less than 16 bytes
for (size_t j = line_end; j < i + 16; ++j) {
std::cout << " ";
}
// Print ASCII representation
std::cout << " |";
for (size_t j = i; j < line_end; ++j) {
unsigned char byte = proxy_start[j];
if (byte >= 32 && byte <= 126) { // Printable ASCII range
std::cout << static_cast<char>(byte);
} else {
std::cout << '.';
}
}
std::cout << "|" << std::endl;
}
std::cout << std::dec << std::endl;
// Additional structured analysis
std::cout << "--- Structured Analysis ---" << std::endl;
// Try to identify different sections of the proxy
if constexpr (sizeof(typename pro::details::facade_traits<F>::meta) <= sizeof(pro::details::ptr_prototype)) {
std::cout << "Meta storage: INLINE (stored directly in proxy)" << std::endl;
std::cout << "Meta section (estimated): bytes 0-" << sizeof(pro::details::ptr_prototype)-1 << std::endl;
std::cout << "Data section (estimated): bytes " << sizeof(pro::details::ptr_prototype) << "-" << sizeof(p)-1 << std::endl;
} else {
std::cout << "Meta storage: INDIRECT (pointer to meta)" << std::endl;
std::cout << "Meta pointer section: bytes 0-" << sizeof(void*)-1 << std::endl;
std::cout << "Data section: bytes " << sizeof(void*) << "-" << sizeof(p)-1 << std::endl;
}
if (dump_size > 32) {
std::cout << "... (showing first 32 bytes only)" << std::endl;
}
}
// Test setup - Enhanced with multiple overloads
PRO_DEF_MEM_DISPATCH(MemDraw, Draw);
PRO_DEF_MEM_DISPATCH(MemArea, Area);
struct MultiOverloadDrawable : pro::facade_builder
::add_convention<MemDraw, void(std::ostream& output)> // Non-const lvalue
::add_convention<MemDraw, void(std::ostream& output) const> // Const lvalue
::add_convention<MemDraw, void(std::ostream& output) &&> // Rvalue
::add_convention<MemArea, double() noexcept> // Different dispatcher
::add_convention<MemArea, double() const noexcept> // Same dispatcher, different const
::add_skill<pro::skills::rtti>
::support_copy<pro::constraint_level::nontrivial>
::build {};
struct Drawable : pro::facade_builder
::add_convention<MemDraw, void(std::ostream& output)>
::add_convention<MemArea, double() noexcept>
::add_skill<pro::skills::rtti>
::support_copy<pro::constraint_level::nontrivial>
::build {};
class Rectangle {
public:
Rectangle(double width, double height) : width_(width), height_(height) {}
Rectangle(const Rectangle&) = default;
void Draw(std::ostream& out) const {
out << "{Rectangle: width = " << width_ << ", height = " << height_ << "}";
}
double Area() const noexcept { return width_ * height_; }
private:
double width_;
double height_;
};
class Circle {
public:
Circle(double radius) : radius_(radius) {}
void Draw(std::ostream& out) const {
out << "{Circle: radius = " << radius_ << "}";
}
double Area() const noexcept { return 3.14159 * radius_ * radius_; }
private:
double radius_;
};
int main() {
std::cout << "=== SINGLE OVERLOAD FACADE ANALYSIS ===" << std::endl;
// Inspect the basic facade structure
facade_inspector<Drawable>::inspect_facade();
// Inspect proxy internal structure
proxy_internal_inspector<Drawable>::inspect_proxy_structure();
std::cout << "\n=== MULTI-OVERLOAD FACADE ANALYSIS ===" << std::endl;
// Compare with multi-overload facade
facade_inspector<MultiOverloadDrawable>::inspect_facade();
// Create some proxy instances
pro::proxy<Drawable> rect_proxy = pro::make_proxy<Drawable, Rectangle>(3.0, 4.0);
pro::proxy<MultiOverloadDrawable> multi_rect = pro::make_proxy<MultiOverloadDrawable, Rectangle>(3.0, 4.0);
// Inspect concrete instances
proxy_internal_inspector<Drawable>::inspect_concrete_instance<Rectangle>(rect_proxy);
// Memory layout inspection
inspect_memory_layout(rect_proxy);
inspect_memory_layout(multi_rect);
// Inspect individual conventions for basic facade
std::cout << "\n=== BASIC FACADE CONVENTIONS ===" << std::endl;
using first_convention = std::tuple_element_t<0, typename Drawable::convention_types>;
using second_convention = std::tuple_element_t<1, typename Drawable::convention_types>;
convention_inspector<first_convention, Drawable>::inspect();
convention_inspector<second_convention, Drawable>::inspect();
// Inspect conventions for multi-overload facade
std::cout << "\n=== MULTI-OVERLOAD FACADE CONVENTIONS ===" << std::endl;
using multi_first_conv = std::tuple_element_t<0, typename MultiOverloadDrawable::convention_types>;
using multi_second_conv = std::tuple_element_t<1, typename MultiOverloadDrawable::convention_types>;
convention_inspector<multi_first_conv, MultiOverloadDrawable>::inspect();
convention_inspector<multi_second_conv, MultiOverloadDrawable>::inspect();
return 0;
}
点击查看代码
=== SINGLE OVERLOAD FACADE ANALYSIS ===
=== FACADE INSPECTION ===
Facade Type: Drawable
Facade Configuration:
max_size: 16 bytes
max_align: 8 bytes
copyability: nontrivial
relocatability: trivial
destructibility: nothrow
Convention Types (size: 3):
Element[0]: pro::v4::details::conv_impl<false, MemDraw, void (std::ostream&)>
Element[1]: pro::v4::details::conv_impl<false, MemArea, double () noexcept>
Element[2]: pro::v4::details::conv_impl<false, pro::v4::details::proxy_cast_dispatch, void (pro::v4::details::proxy_cast_context) &, void (pro::v4::details::proxy_cast_context) const &, void (pro::v4::details::proxy_cast_context) &&>
Reflection Types (size: 1):
Element[0]: pro::v4::details::refl_impl<false, pro::v4::details::proxy_typeid_reflector>
=== PROXY INTERNAL STRUCTURE ===
Proxy Type: pro::v4::proxy<Drawable>
Meta Type: pro::v4::details::composite_meta<pro::v4::details::invocation_meta<Drawable, true, pro::v4::details::copy_dispatch, void (pro::v4::proxy<Drawable>&) const>, pro::v4::details::invocation_meta<Drawable, true, pro::v4::details::destroy_dispatch, void () noexcept>, pro::v4::details::invocation_meta<Drawable, false, MemDraw, void (std::ostream&)>, pro::v4::details::invocation_meta<Drawable, false, MemArea, double () noexcept>, pro::v4::details::invocation_meta<Drawable, false, pro::v4::details::proxy_cast_dispatch, void (pro::v4::details::proxy_cast_context) &>, pro::v4::details::invocation_meta<Drawable, false, pro::v4::details::proxy_cast_dispatch, void (pro::v4::details::proxy_cast_context) const &>, pro::v4::details::invocation_meta<Drawable, false, pro::v4::details::proxy_cast_dispatch, void (pro::v4::details::proxy_cast_context) &&>, pro::v4::details::refl_meta<false, pro::v4::details::proxy_typeid_reflector> >
Indirect Accessor: pro::v4::details::composite_accessor<MemDraw::accessor<pro::v4::proxy_indirect_accessor<Drawable>, MemDraw, void (std::ostream&)>, MemArea::accessor<pro::v4::proxy_indirect_accessor<Drawable>, MemArea, double () noexcept>, pro::v4::details::proxy_cast_dispatch::accessor<pro::v4::proxy_indirect_accessor<Drawable>, pro::v4::details::proxy_cast_dispatch, void (pro::v4::details::proxy_cast_context) &, void (pro::v4::details::proxy_cast_context) const &, void (pro::v4::details::proxy_cast_context) &&>, pro::v4::details::proxy_typeid_reflector::accessor<pro::v4::proxy_indirect_accessor<Drawable>, pro::v4::details::proxy_typeid_reflector> >
Direct Accessor: pro::v4::details::composite_accessor<>
Meta Pointer Type: pro::v4::details::meta_ptr_indirect_impl<pro::v4::details::composite_meta<pro::v4::details::invocation_meta<Drawable, true, pro::v4::details::copy_dispatch, void (pro::v4::proxy<Drawable>&) const>, pro::v4::details::invocation_meta<Drawable, true, pro::v4::details::destroy_dispatch, void () noexcept>, pro::v4::details::invocation_meta<Drawable, false, MemDraw, void (std::ostream&)>, pro::v4::details::invocation_meta<Drawable, false, MemArea, double () noexcept>, pro::v4::details::invocation_meta<Drawable, false, pro::v4::details::proxy_cast_dispatch, void (pro::v4::details::proxy_cast_context) &>, pro::v4::details::invocation_meta<Drawable, false, pro::v4::details::proxy_cast_dispatch, void (pro::v4::details::proxy_cast_context) const &>, pro::v4::details::invocation_meta<Drawable, false, pro::v4::details::proxy_cast_dispatch, void (pro::v4::details::proxy_cast_context) &&>, pro::v4::details::refl_meta<false, pro::v4::details::proxy_typeid_reflector> > >
Storage Details:
Storage size: 16 bytes
Storage alignment: 8 bytes
Actual proxy size: 24 bytes
Meta storage: INDIRECT (pointer)
=== MULTI-OVERLOAD FACADE ANALYSIS ===
=== FACADE INSPECTION ===
Facade Type: MultiOverloadDrawable
Facade Configuration:
max_size: 16 bytes
max_align: 8 bytes
copyability: nontrivial
relocatability: trivial
destructibility: nothrow
Convention Types (size: 3):
Element[0]: pro::v4::details::conv_impl<false, MemDraw, void (std::ostream&), void (std::ostream&) const, void (std::ostream&) &&>
Element[1]: pro::v4::details::conv_impl<false, MemArea, double () noexcept, double () noexcept const>
Element[2]: pro::v4::details::conv_impl<false, pro::v4::details::proxy_cast_dispatch, void (pro::v4::details::proxy_cast_context) &, void (pro::v4::details::proxy_cast_context) const &, void (pro::v4::details::proxy_cast_context) &&>
Reflection Types (size: 1):
Element[0]: pro::v4::details::refl_impl<false, pro::v4::details::proxy_typeid_reflector>
=== CONCRETE INSTANCE INSPECTION ===
Stored Concrete Type: Rectangle
Meta object address: 0x40e880
Stored object address: 0x7fffffffd3a0
Successfully accessed stored object!
=== MEMORY LAYOUT INSPECTION ===
Proxy object starts at: 0x7fffffffd430
Proxy object size: 24 bytes
Has value: true
--- Raw Memory Dump ---
Offset 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ASCII
--------------------------------------------------------------
0000: 80 e8 40 00 00 00 00 00 00 00 00 00 00 00 08 40 |..@............@|
0010: 00 00 00 00 00 00 10 40 |.......@|
--- Structured Analysis ---
Meta storage: INDIRECT (pointer to meta)
Meta pointer section: bytes 0-7
Data section: bytes 8-23
=== MEMORY LAYOUT INSPECTION ===
Proxy object starts at: 0x7fffffffd410
Proxy object size: 24 bytes
Has value: true
--- Raw Memory Dump ---
Offset 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ASCII
--------------------------------------------------------------
0000: c0 e8 40 00 00 00 00 00 00 00 00 00 00 00 08 40 |..@............@|
0010: 00 00 00 00 00 00 10 40 |.......@|
--- Structured Analysis ---
Meta storage: INDIRECT (pointer to meta)
Meta pointer section: bytes 0-7
Data section: bytes 8-23
=== BASIC FACADE CONVENTIONS ===
=== CONVENTION INSPECTION ===
Convention Type: pro::v4::details::conv_impl<false, MemDraw, void (std::ostream&)>
Is Direct: false
Dispatch Type: MemDraw
Overload Types (size: 1):
Element[0]: void (std::ostream&)
This dispatcher handles 1 overload(s):
--- Overload 0 Analysis ---
Signature: : void (std::ostream&)
Return type: : void
Qualifier: lvalue reference (&)
Dispatcher function type: : void (*)(pro::v4::proxy<Drawable>&, std::ostream&)
Dispatcher size: 8 bytes
=== CONVENTION INSPECTION ===
Convention Type: pro::v4::details::conv_impl<false, MemArea, double () noexcept>
Is Direct: false
Dispatch Type: MemArea
Overload Types (size: 1):
Element[0]: double () noexcept
This dispatcher handles 1 overload(s):
--- Overload 0 Analysis ---
Signature: : double () noexcept
Return type: : double
Qualifier: lvalue reference (&)
Dispatcher function type: : double (*)(pro::v4::proxy<Drawable>&) noexcept
Dispatcher size: 8 bytes
=== MULTI-OVERLOAD FACADE CONVENTIONS ===
=== CONVENTION INSPECTION ===
Convention Type: pro::v4::details::conv_impl<false, MemDraw, void (std::ostream&), void (std::ostream&) const, void (std::ostream&) &&>
Is Direct: false
Dispatch Type: MemDraw
Overload Types (size: 3):
Element[0]: void (std::ostream&)
Element[1]: void (std::ostream&) const
Element[2]: void (std::ostream&) &&
This dispatcher handles 3 overload(s):
--- Overload 0 Analysis ---
Signature: : void (std::ostream&)
Return type: : void
Qualifier: lvalue reference (&)
Dispatcher function type: : void (*)(pro::v4::proxy<MultiOverloadDrawable>&, std::ostream&)
Dispatcher size: 8 bytes
--- Overload 1 Analysis ---
Signature: : void (std::ostream&) const
Return type: : void
Qualifier: const lvalue reference (const &)
Dispatcher function type: : void (*)(pro::v4::proxy<MultiOverloadDrawable> const&, std::ostream&)
Dispatcher size: 8 bytes
--- Overload 2 Analysis ---
Signature: : void (std::ostream&) &&
Return type: : void
Qualifier: rvalue reference (&&)
Dispatcher function type: : void (*)(pro::v4::proxy<MultiOverloadDrawable>&&, std::ostream&)
Dispatcher size: 8 bytes
=== CONVENTION INSPECTION ===
Convention Type: pro::v4::details::conv_impl<false, MemArea, double () noexcept, double () noexcept const>
Is Direct: false
Dispatch Type: MemArea
Overload Types (size: 2):
Element[0]: double () noexcept
Element[1]: double () noexcept const
This dispatcher handles 2 overload(s):
--- Overload 0 Analysis ---
Signature: : double () noexcept
Return type: : double
Qualifier: lvalue reference (&)
Dispatcher function type: : double (*)(pro::v4::proxy<MultiOverloadDrawable>&) noexcept
Dispatcher size: 8 bytes
--- Overload 1 Analysis ---
Signature: : double () noexcept const
Return type: : double
Qualifier: const lvalue reference (const &)
Dispatcher function type: : double (*)(pro::v4::proxy<MultiOverloadDrawable> const&) noexcept
Dispatcher size: 8 bytes
facade
以下均以 Drawable 为例,其它的类似
我们 demangle facade 也能得到它的类型 Drawable
首先 convention_types, reflection_types 是在 facade 下面的,内容如下
convention_types 是
tuple<
conv_impl<false, MemDraw, void (std::ostream&)>,
conv_impl<false, MemArea, double () noexcept>,
conv_impl<false, proxy_cast_dispatch, void (proxy_cast_context) &, void (proxy_cast_context) const &, void (proxy_cast_context) &&>
>
reflection_types 是
tuple<
refl_impl<false, proxy_typeid_reflector>
>
前面两个很好理解,就是在add_convention注册的内容
第三条 convention,以及 reflection,都是注册 rtti 带来的
阅读源码可以发现 skill 有 indirect_rtti(rtti), direct_rtti, slim, as_view, as_weak 这几种,而且都是 add_(in)direct_convention 的 wrapper,不知道为什么要切出来
那么 reflection 是哪来的?
我们可以试着改成别的 skills 比如 as_view,然后发现没有 reflection 了
仔细看,只有 rtti 是调用 add_indirect_convention 的,而别的都是 direct,大概就是这样加入refl_impl<false, R>,后面把refl_impl<true, R>给剔除就行
proxy
它的 meta 类型如下
composite_meta<
invocation_meta<Drawable, true, copy_dispatch, void (proxy<Drawable>&) const>,
invocation_meta<Drawable, true, destroy_dispatch, void () noexcept>,
invocation_meta<Drawable, false, MemDraw, void (std::ostream&)>,
invocation_meta<Drawable, false, MemArea, double () noexcept>,
invocation_meta<Drawable, false, proxy_cast_dispatch, void (proxy_cast_context) &>,
invocation_meta<Drawable, false, proxy_cast_dispatch, void (proxy_cast_context) const &>,
invocation_meta<Drawable, false, proxy_cast_dispatch, void (proxy_cast_context) &&>,
refl_meta<false, proxy_typeid_reflector>
>
第一条是support_copy,第二条是默认带的析构,第三四条是我们加的 convention
后面全是 rtti 的,注意 add_indirect_convention 这里是会把写的重载全部加进去
invocation_meta主要的作用是在invoke_impl用来拿到 dispatcher,也就是具体的函数
它的 indirect accessor 类型如下,相当的一目了然
composite_accessor<
MemDraw::accessor<proxy_indirect_accessor<Drawable>, MemDraw, void (std::ostream&)>,
MemArea::accessor<proxy_indirect_accessor<Drawable>, MemArea, double () noexcept>,
proxy_cast_dispatch::accessor<
proxy_indirect_accessor<Drawable>,
proxy_cast_dispatch,
void (proxy_cast_context) &,
void (proxy_cast_context) const &,
void (proxy_cast_context) &&
>,
proxy_typeid_reflector::accessor<
proxy_indirect_accessor<Drawable>,
proxy_typeid_reflector
>
>
accessor 类型如下,为空
composite_accessor<>
meta pointer 类型如下,其实就是在 meta 外面再包一层
meta_ptr_indirect_impl<
composite_meta<
invocation_meta<Drawable, true, copy_dispatch, void (proxy<Drawable>&) const>,
invocation_meta<Drawable, true, destroy_dispatch, void () noexcept>,
invocation_meta<Drawable, false, MemDraw, void (std::ostream&)>,
invocation_meta<Drawable, false, MemArea, double () noexcept>,
invocation_meta<Drawable, false, proxy_cast_dispatch, void (proxy_cast_context) &>,
invocation_meta<Drawable, false, proxy_cast_dispatch, void (proxy_cast_context) const &>,
invocation_meta<Drawable, false, proxy_cast_dispatch, void (proxy_cast_context) &&>,
refl_meta<false, proxy_typeid_reflector>
>
>
detail
我们取第一个 convention
它的 dispatch_type 是 MemDraw,没什么好说的
它的 overload_types 是 void (std::ostream&),注意这里是 types
如果换成 rtti 那条 convention,我们理论上可以得到void (proxy_cast_context) &, void (proxy_cast_context) const &, void (proxy_cast_context) &&这样的东西,不过需要改下代码
然后我们取第一个 dispatcher,不过这个相当简单,基本是就是看一下 parse 出了什么
Performance
Proxy 首先当然是非侵入的组合来达到多态,这一点从上面的样例就能看出来
但是都写 C++ 了,性能还是得看的吧
虽然说虚函数开销大,但是在现代编译器和CPU的加持下其实也就10-20个周期,看上去开销也不大
总之作者声称这个开销全方位的优于虚函数,包括反编译代码也是,不过也有一些评论指出实际的性能似乎并没有那么好
There is a negligible beginning in all great action and thought.

浙公网安备 33010602011771号