ไลบรารีสำหรับความหลากหลายแบบไดนามิกที่มีประสิทธิภาพผ่านการลบประเภท (C ++ 17 หรือใหม่กว่า)
เป้าหมายคือประสิทธิภาพ ความเข้าใจ และความสามารถในการขยายได้
เสียงดังกราว, gcc, msvc
How to build?
พื้นฐานของการลบประเภทไลบรารีคือ Method ซึ่งเป็นคำอธิบายว่าส่วนใดของประเภทที่เราต้องการใช้หลังจากการลบ
มาสร้างอันหนึ่งเพื่อลบประเภทด้วย void draw()
:
มีมาโคร anyany_method
ใน <anyany/anyany_macro.hpp> ตัวอย่างเช่น สำหรับ Method 'foo' ซึ่งยอมรับ int และ float + return float
# include < anyany/anyany_macro.hpp >
anyany_method (foo, (&self, int i, float f) requires(self.foo(i, f)) -> float);
...
void example (aa::any_with<foo> obj) {
if (obj. has_value ())
float x = obj. foo ( 5 , 3 . 14f ); // all works
obj = some_type_with_foo{};
obj = some_other_type_with_foo ();
}
// For each type T do value.draw()
struct Draw {
template < typename T>
static void do_invoke ( const T& self) {
self. draw ();
}
};
เราสามารถใช้ Draw
เพื่อลบประเภท:
# include < anyany/anyany.hpp >
using any_drawable = aa::any_with<Draw>;
และตอนนี้เราสามารถใช้ any_drawable
เพื่อจัดเก็บประเภทใดก็ได้ด้วย .draw()
// some types with .draw()
struct Circle {
void draw () const {
std::cout << " Draw Circle n " ;
}
};
struct Square {
void draw () const {
std::cout << " Draw Square n " ;
}
};
int main () {
any_drawable shape = Circle{};
aa::invoke<Draw>(shape); // prints "Draw Circle"
shape = Square{};
aa::invoke<Draw>(shape); // prints "Draw Square"
// see /examples folder for more
}
ไม่มีฟังก์ชันเสมือน การสืบทอด พอยน์เตอร์ การจัดการหน่วยความจำ ฯลฯ! ดี!
คุณสามารถเพิ่ม วิธีการ ได้หลายวิธี:
using any_my = aa::any_with<Draw, Run, aa::copy>;
รอคัดลอก...? ใช่ โดยค่าเริ่มต้น aa::any_with
มีเพียง destructor คุณสามารถเพิ่ม aa::copy
วิธีการคัดลอกและเคลื่อนย้ายได้หรือ aa::move
เพื่อให้ย้ายเท่านั้น
วิธีการ ที่กำหนดไว้ล่วงหน้า :
ทำให้ any_with
คัดลอกและเคลื่อนย้ายได้ เปิดใช้งาน aa::materialize
สำหรับการอ้างอิง (ซึ่งต้องใช้วิธี aa::destroy
ด้วย)
นอกจากนี้ยังมี copy_with<Alloc, SooS>
ซึ่งเปิดใช้งานการคัดลอกเมื่อคุณใช้ Allocator แบบกำหนดเองและ Small Object Optimization Size( aa::basic_any_with
)
ทำให้ 'any_with' สามารถเคลื่อนย้ายได้
หมายเหตุ: ย้ายตัวสร้างและย้ายตัวดำเนินการกำหนดสำหรับ any_with
โดยไม่มีการยกเว้นเสมอ
เปิดใช้งานความเชี่ยวชาญพิเศษ std::hash
สำหรับ any_with
, poly_ref
/...etc ถ้า any_with
ว่างเปล่า ดังนั้น hash == 0
หมายเหตุ: poly_ptr
มีความเชี่ยวชาญพิเศษของ std::hash
ตามค่าเริ่มต้น แต่เป็นแฮชที่เหมือนตัวชี้
เปิดใช้งาน aa::any_cast
, aa::type_switch
, aa::visit_invoke
โดยการเพิ่ม RTTI ใน vtable
เพิ่ม .type_descriptor() -> aa::descriptor_t
สำหรับ any_with
/ poly_ref
/...etc ด้วย
เปิดใช้ operator==
สำหรับ any_with
/ poly_ref
/...etc
วัตถุสองชิ้นจะเท่ากันหากมีประเภทเดียวกัน (หรือว่างทั้งคู่) และค่าที่เก็บไว้จะเท่ากัน
เปิดใช้ operator<=>
และ operator==
สำหรับ any_with
/ poly_ref
/...etc
หมายเหตุ: ตัวดำเนินการ<=> ส่งคืน std::partial_ordering
เสมอ
หากวัตถุสองรายการไม่มีประเภทเดียวกันจะส่งคืน unordered
มิฉะนั้นจะส่งคืนผลลัพธ์ของ operator <=>
สำหรับวัตถุที่มีอยู่
หมายเหตุ: ส่งคืน std::partial_ordering::equivalent
ถ้าทั้งคู่ว่างเปล่า
เพิ่ม R operator()(Args...)
สำหรับ any_with
/ poly_ref
/...etc
หมายเหตุ: รองรับลายเซ็น const
, noexcept
และ const noexcept
ด้วย
ตัวอย่าง:
// stateful::cref is a lightweight thing,
// it stores vtable in itself(in this case only one function ptr)
// and const void* to value
// This is most effective way to erase function
template < typename Signature>
using function_ref = aa::stateful::cref<aa::call<Signature>>;
void foo (function_ref< int ( float ) const > ref) {
int result = ref ( 3.14 );
}
เพิ่ม destructor ( any_with
เป็นค่าเริ่มต้น) แต่บางทีคุณอาจต้องการใช้กับ aa::poly_ptr
เพื่อจัดการอายุการใช้งานด้วยตนเอง ยังเปิดใช้งาน aa::materialize
สำหรับการอ้างอิง (ต้องใช้ aa::copy ด้วย)
ดูแนวคิด method
ใน anyany.hpp หากคุณต้องการรายละเอียดทั้งหมดเกี่ยวกับ วิธีการ
ประเภทโพลีมอร์ฟิก:
any_with<Methods...>
basic_any_with<Methods...>
poly_ref<Methods...>
poly_ptr<Methods...>
cref<Methods...>
cptr<Methods...>
stateful::ref<Methods...>
stateful::cref<Methods...>
การดำเนินการ:
any_cast<T>
invoke<Method>
type_switch
visit_invoke
ภาชนะโพลีมอร์ฟิก:
variant_swarm<Ts...>
data_parallel_vector<T, Alloc>
template < typename T>
concept method = /* ... */ ; // see anyany.hpp
// true if type can be used as poly traits argument in any_cast / type_switch / visit_invoke etc
template < typename T>
concept poly_traits = requires(T val, int some_val) {
{ val. get_type_descriptor (some_val) } -> std::same_as< descriptor_t >;
{ val. to_address (some_val) };
};
คุณสามารถกำหนดลักษณะสำหรับลำดับชั้นแบบโพลีมอร์ฟิกของคุณได้ (รหัสประเภทที่คล้าย LLVM, ฟังก์ชันไวรัส ฯลฯ)
ห้องสมุดมีคุณสมบัติดังกล่าวสองประการในตัว (คุณสามารถใช้เป็นตัวอย่างในการนำไปใช้ของคุณเอง):
ตัวอย่างเช่น คุณต้องการให้เมธอด .foo() เป็นประเภทที่สร้างโดย any_with
หรือ poly_ref
ด้วย Method ของคุณ
จากนั้นคุณควรใช้ plugins
:
struct Foo {
template < typename T>
static void do_invoke (T&) { /* do something */ }
// any_with<Foo> will inherit plugin<any_with<Foo>>
template < typename CRTP>
struct plugin {
void foo () const {
auto & self = * static_cast < const CRTP*>( this );
// Note: *this may not contain value, you can check it by calling self.has_value()
aa::invoke<Foo>(self);
}
};
};
//
any_with<Foo> val = /* ... */ ;
val.foo(); // we have method .foo from plugin!
หมายเหตุ: คุณสามารถ 'เงา/แทนที่' ปลั๊กอินอื่นๆ ได้โดยสืบทอดจากปลั๊กอินเหล่านั้นในปลั๊กอินของคุณ (แม้ว่าการสืบทอดจะเป็นแบบส่วนตัวก็ตาม)
ดูตัวอย่าง aa::spaceship/aa::copy_with ปลั๊กอิน
นอกจากนี้คุณยังสามารถเชี่ยวชาญ aa::plugin<Any, Method> สำหรับวิธีการของคุณหรือแม้กระทั่งสำหรับ 'Any' ด้วยข้อกำหนดบางประการ
any_with
ยอมรับ วิธีการ จำนวนเท่าใดก็ได้ และสร้างประเภทที่สามารถเก็บค่าใดๆ ก็ได้ ซึ่งสนับสนุน วิธีการ เหล่านั้น คล้ายกับแนวคิดรันไทม์
หมายเหตุ: มีแท็ก 'aa::force_stable_pointers' เพื่อบังคับการจัดสรร ดังนั้น poly_ptr/cptr
ไปยัง any_with<...>
จะไม่ถูกยกเลิกหลังจากการย้าย
หมายเหตุ: aa::unreachable_allocator
ซึ่งจะหยุดการคอมไพล์หาก basic_any_with<unreachable_allocator, ...>
พยายามจัดสรรหน่วยความจำ ดังนั้นคุณจึงสามารถบังคับไม่จัดสรรเป็นประเภทได้
// All constructors and move assign operators are exception safe
// move and move assign always noexcept
// See 'construct_interface' alias in anyany.hpp and 'struct plugin'for details how it works(comments)
struct Any : construct_interface<basic_any<Alloc, SooS, Methods...>, Methods...>{
// aliases to poly ref/ptr
using ptr = /* ... */ ;
using ref = /* ... */ ;
using const_ptr = /* ... */ ;
using const_ref = /* ... */ ;
// operator & for getting poly ptr
poly_ptr<Methods...> operator &() noexcept ;
const_poly_ptr<Methods...> operator &() const noexcept ;
// main constructors
// creates empty
constexpr Any ();
Any ( auto && value); // from any type
Any ( const Any&) requires aa::copy
Any& operator =( const Any&) requires aa::move and aa::copy
Any (Any&&) noexcept requires aa::move;
Any& operator =(Any&&) requires method aa::move;
// observers
bool has_value () const noexcept ;
// returns true if poly_ptr/ref to *this will not be invalidated after moving value
bool is_stable_pointers () const noexcept
// returns count of bytes sufficient to store current value
// (not guaranteed to be smallest)
// return 0 if !has_value()
size_t sizeof_now() const noexcept ;
// returns descriptor_v<void> if value is empty
type_descriptor_t type_descriptor () const noexcept requires aa::type_info;
// forces that after creation is_stable_pointers() == true (allocates memory)
template < typename T>
Any ( force_stable_pointers_t , T&& value);
// also emplace constructors(std::in_place_type_t<T>), initiaizer list versions
// same with force_stable_pointers_t tag etc etc
// same with Alloc...
// modifiers
// emplaces value in any, if exception thrown - any is empty(use operator= if you need strong exception guarantee here)
template < typename T, typename ... Args>
std:: decay_t <T>& emplace (Args&&...); // returns reference to emplaced value
template < typename T, typename U, typename ... Args>
std:: decay_t <T>& emplace (std::initializer_list<U> list, Args&&... args)
// postcondition: has_value() == false
void reset() noexcept ;
// see aa::equal_to description for behavior
bool operator ==( const Any&) const requires aa::spaceship || aa::equal_to;
// see aa::spaceship description for behavior
std::partial_ordering operator <=>( const Any&) const requires aa::spaceship;
// ... interface from plugins for Methods if presented ...
};
ตัวสร้างและผู้ดำเนินการมอบหมายงานคัดลอก/ย้ายทั้งหมดมีการรับประกันข้อยกเว้นที่เข้มงวด
หมายเหตุ: หากประเภทของคุณไม่มียกเว้นตัวสร้างการย้าย มันสามารถเพิ่มประสิทธิภาพได้จริง (เช่นในกรณี std::vector)
ตัวอย่าง:
using any_printable = aa::any_with<Print, aa::move>;
basic_any_with
เช่นเดียวกับ any_with
แต่ด้วยการจัดสรรแบบกำหนดเองและขนาดบัฟเฟอร์การเพิ่มประสิทธิภาพออบเจ็กต์ขนาดเล็ก - หากคุณต้องการ basic_any_with
ที่คัดลอกได้ให้ใช้ copy_with
template < typename Alloc, size_t SooS, TTA... Methods>
using basic_any_with = /* ... */ ;
poly_ref
ไม่ได้เป็นเจ้าของ ไม่เป็นโมฆะเสมอ น้ำหนักเบา(~=void*)
poly_ref<Methods...>
สามารถแปลงเป็นจำนวนเมธอดที่น้อยลงโดยปริยายได้
poly_ref<A, B, C>
สามารถแปลงเป็น poly_ref<A, B>
, poly_ref<A>
, poly_ref<B>
... ฯลฯ เป็นต้น
ซึ่งหมายความว่าคุณสามารถเพิ่มอินเทอร์เฟซของฟังก์ชันเฉพาะ วิธีการ ที่ต้องการจริงๆ เท่านั้น หากคุณเพิ่ม Method ให้กับประเภท any_with
ของคุณจะไม่มีการแตก abi/api
// you can invoke this function with any poly_ref<..., A, ...>
void foo (poly_ref<A>);
template < template < typename > typename ... Methods>
struct poly_ref {
poly_ref ( const poly_ref&) = default ;
poly_ref (poly_ref&&) = default ;
poly_ref& operator =(poly_ref&&) = default ;
poly_ref& operator =( const poly_ref&) = default ;
// only explicit rebind reference after creation
void operator =( auto &&) = delete ;
descriptor_t type_descriptor () const noexcept requires aa::type_info;
// from mutable lvalue
template <not_const_type T> // not shadow copy ctor
poly_ref (T& value) noexcept
poly_ptr<Methods...> operator &() const noexcept ;
// ... interface from plugins for Methods if presented ...
}
const_poly_ref
เหมือนกับ poly_ref
แต่สามารถสร้างได้จาก poly_ref
และ const T&
aa::cref
เป็นนามแฝงเทมเพลตของ aa::const_poly_ref
หมายเหตุ: ไม่ยืดอายุการใช้งาน
poly_ptr
ไม่ได้เป็นเจ้าของ, เป็นโมฆะ, น้ำหนักเบา(~=void*)
poly_ptr<Methods...>
แปลงโดยปริยายให้มีจำนวนเมธอดน้อยลง
poly_ptr<A, B, C>
สามารถแปลงเป็น poly_ptr<A, B>
, poly_ptr<A>
, poly_ptr<B>
... ฯลฯ เป็นต้น
ซึ่งหมายความว่าคุณสามารถเพิ่มอินเทอร์เฟซของฟังก์ชันเฉพาะ วิธีการ ที่ต้องการจริงๆ เท่านั้น หากคุณเพิ่ม Method ให้กับประเภท any_with
ของคุณจะไม่มีการแตก abi/api
// you can invoke this function with any poly_ptr<..., A, ...>
void foo (poly_ptr<A>);
หมายเหตุ: poly_ptr
และ const_poly_ptr
สามารถคัดลอกได้เล็กน้อย ดังนั้น std::atomic<poly_ptr<...>>
จึงใช้งานได้
template < template < typename > typename ... Methods>
struct poly_ptr {
poly_ptr () = default ;
poly_ptr (std:: nullptr_t ) noexcept ;
poly_ptr& operator =(std:: nullptr_t ) noexcept ;
poly_ptr (not_const_type auto * ptr) noexcept ;
// from non-const pointer to Any with same methods
template <any_x Any>
poly_ptr (Any* ptr) noexcept ;
// observers
// returns raw pointer to value
void * raw () const noexcept ;
// NOTE: returns unspecified value if *this == nullptr
const vtable<Methods...>* raw_vtable_ptr () const noexcept ;
// returns descriptor_v<void> is nullptr
descriptor_t type_descriptor () const noexcept requires aa::type_info;
bool has_value () const noexcept ;
bool operator ==(std:: nullptr_t ) const noexcept ;
explicit operator bool () const noexcept ;
// similar to common pointer operator* returns reference
poly_ref<Methods...> operator *() const noexcept ;
const poly_ref<Methods...>* operator ->() const noexcept ;
}
const_poly_ptr
เช่นเดียวกับ poly_ptr
แต่สามารถสร้างได้จาก poly_ptr
และ const T*
/ Any*
aa::cptr
เป็นเทมเพลตนามแฝงของ aa::const_poly_ptr
stateful_ref
aa::stateful::ref<Methods...>
มี vtable อยู่ในตัวเอง
นอกจากนี้ยังสามารถมีการอ้างอิงถึงอาร์เรย์ C และฟังก์ชันโดยไม่สลายตัว
มันมีอินเทอร์เฟซที่ค่อนข้างเรียบง่าย สร้างจาก T&/poly_ref
และเรียกใช้เท่านั้น (เช่น aa::intake เป็นต้น)
มันจะมีประสิทธิภาพสูงสุดหากคุณต้องการลบเมธอด 1-2 วิธี และไม่จำเป็นต้องใช้ any_cast
กรณีการใช้งานทั่วไป - การสร้าง function_ref
template < typename Signature>
using function_ref = aa::stateful::cref<aa::call<Signature>>;
bool foo ( int ) { return true ; }
void example (function_ref< bool ( int ) const > ref) {
ref ( 5 );
}
int main () {
example (&foo);
example ([]( int x) { return false ; });
}
stateful_cref
เหมือนกับ stateful::ref
แต่อาจถูกสร้างขึ้นจาก const T&
และ aa::cref
any_cast
ต้องใช้วิธี aa::type_info
วัตถุการทำงานที่มีตัวดำเนินการ ():
ทำงานเป็น std::any_cast - คุณสามารถแปลงเป็น T(copy), T&(take ref) (พ่น aa::bad_cast ถ้าการร่ายไม่ดี)
หรือคุณสามารถส่งพอยน์เตอร์ (หรือ poly_ptr) (ส่งคืน nullptr หากการส่งไม่ดี)
T* ptr = any_cast<T>(&any);
ตัวอย่าง:
using any_comparable = aa::any_with<aa::copy, aa::spaceship, aa::move>;
void Foo () {
any_comparable value = 5 ;
value. emplace <std::vector< int >>({ 1 , 2 , 3 , 4 }); // constructed in-place
// any_cast returns pointer to vector<int>(or nullptr if any do not contain vector<int>)
aa::any_cast<std::vector< int >>( std::addressof (value))-> back () = 0 ;
// version for reference
aa::any_cast<std::vector< int >&>(value). back () = 0 ;
// version which returns by copy (or move, if 'value' is rvalue)
auto vec = aa::any_cast<std::vector< int >>(value);
}
invoke
วัตถุฟังก์ชั่นที่มีตัวดำเนินการ () ซึ่งยอมรับ any_with/ref/cref/stateful::ref/stateful::cref
เป็นอาร์กิวเมนต์แรกจากนั้นอาร์กิวเมนต์ของ เมธอด ทั้งหมดและเรียกใช้ เมธอด
หาก arg เป็น const any_with
หรือ cref
แสดงว่าอนุญาตเฉพาะ วิธี const เท่านั้น
เงื่อนไขเบื้องต้น: any.has_value() == true
ตัวอย่าง:
void example (any_with<Say> pet) {
if (!pet. has_value ())
return ;
// invokes Method `Say`, passes std::cout as first argument
aa::invoke<Say>(pet, std::cout);
}
void foo (std::vector<aa::poly_ref<Foo>> vec) {
// invokes Method `Foo` without arguments for each value in `vec`
std::ranges::for_each (vec, aa::invoke<Foo>);
}
type_switch
เลือก .case ตามประเภทไดนามิก arg อินพุต และเรียกใช้ visitor
ด้วยประเภทไดนามิกหรือฟังก์ชันเริ่มต้นนี้
นอกจากนี้ยังรองรับ poly_traits
เป็นอาร์กิวเมนต์เทมเพลตที่สองด้วย ดังนั้นจึงรองรับประเภทใดก็ได้ที่คุณมีคุณสมบัติ poly
template < typename Result = void , poly_traits Traits = anyany_poly_traits>
struct type_switch_fn {
type_switch_fn (poly_ref<...>);
// invokes Fn if T contained
template < typename T, typename Fn>
type_switch_impl& case_ (Fn&& f);
// If value is one of Ts... F invoked (invokes count <= 1)
template < typename ... Ts, typename Fn>
type_switch_impl& cases (Fn&& f);
// if no one case succeded invokes 'f' with input poly_ref argument
template < typename Fn>
Result default_ (Fn&& f);
// if no one case succeded returns 'v'
Result default_ (Result v);
// if no one case succeded returns 'nullopt'
std::optional<Result> no_default ();
};
ตัวอย่าง:
Result val = aa::type_switch<Result>(value)
.case_< float >(foo1)
.case_< bool >(foo2)
.cases< char , int , unsigned char , double >(foo3)
.default_( 15 );
visit_invoke
มัน... ความละเอียดโอเวอร์โหลดรันไทม์! aa::make_visit_invoke<Foos...>
สร้างวัตถุชุดโอเวอร์โหลดด้วยวิธี .resolve(Args...)
ซึ่งดำเนินการแก้ไขโอเวอร์โหลดตาม Args... ประเภทรันไทม์
แก้ไขคืนค่า nullopt
หากไม่มีฟังก์ชันดังกล่าวเพื่อยอมรับอาร์กิวเมนต์อินพุต
ตัวอย่างนี้เป็นพื้นฐานมาก โปรดดู /examples/visit_invoid_example.hpp เพิ่มเติม
ตัวอย่าง:
auto ship_asteroid = [](spaceship s, asteroid a) -> std::string { ... }
auto ship_star = [](spaceship s, star) -> std::string { ... }
auto star_star = [](star a, star b) -> std::string { ... }
auto ship_ship = [](spaceship a, spaceship b) -> std::string { ... }
// Create multidispacter
constexpr inline auto collision = aa::make_visit_invoke<std::string>(
ship_asteroid,
ship_star,
star_star,
ship_ship);
...
// Perform runtime overload resolution
std::optional<std::string> foo (any_with<A> a, any_with<B> b) {
return collision. resolve (a, b);
}
variant_swarm
อะแดปเตอร์คอนเทนเนอร์ Polymorphic ซึ่งทำงานเป็น Container<std::variant<Types...>>
แต่มีประสิทธิภาพมากกว่ามาก
รองรับการดำเนินงาน:
visit<Types...>(visitor)
- เรียก visitor
โดยมีค่าประเภท Types
ที่มีอยู่ทั้งหมดview<T>
- ส่งคืนการอ้างอิงไปยังคอนเทนเนอร์ของค่าที่เก็บไว้ทั้งหมดประเภท T
คอนเทนเนอร์เป็น std::vector
โดยค่าเริ่มต้น
template < template < typename > typename Container, typename ... Ts>
struct basic_variant_swarm {
// modifiers
void swap (basic_variant_swarm& other) noexcept ;
friend void swap (basic_variant_swarm& a, basic_variant_swarm& b) noexcept ;
// selects right container and inserts [it, sent) into it
template <std::input_iterator It>
requires (tt::one_of<std:: iter_value_t <It>, std::ranges:: range_value_t <Container<Ts>>...>)
auto insert (It it, It sent);
// insert and erase overloads for each type in Ts...
using inserters_type::erase;
using inserters_type::insert;
// observe
bool empty () const noexcept ;
// returns count values, stored in container for T
template <tt::one_of<Ts...> T>
requires (std::ranges::sized_range<container_for<T>>)
auto count () const ;
template <std:: size_t I>
requires (std::ranges::sized_range<decltype(std::get<I>(containers))>)
auto count () const ;
// returns count of values stored in all containers
constexpr auto size () const requires(std::ranges::sized_range<container_for<Ts>> && ...);
// returns tuple of reference to containers #Is
template <std:: size_t ... Is>
auto view ();
template <std:: size_t ... Is>
auto view () const ;
// returns tuple of reference to containers for Types
template <tt::one_of<Ts...>... Types>
auto view ();
template <tt::one_of<Ts...>... Types>
auto view () const ;
// visit
// visits with 'v' and passes its results into 'out_visitor' (if result is not void)
template <tt::one_of<Ts...>... Types>
void visit (visitor_for<Types...> auto && v, auto && out_visitor);
// ignores visitor results
template <tt::one_of<Ts...>... Types>
void visit (visitor_for<Types...> auto && v);
// visits with 'v' and passes its results into 'out_visitor' (if result is not void)
void visit_all (visitor_for<Ts...> auto && v, auto && out_visitor);
// ignores visitor results
constexpr void visit_all (visitor_for<Ts...> auto && v);
template <tt::one_of<Ts...>... Types, std::input_or_output_iterator Out>
constexpr Out visit_copy (visitor_for<Types...> auto && v, Out out);
template <tt::one_of<Ts...>... Types, std::input_or_output_iterator Out>
constexpr Out visit_copy (Out out);
// visits with 'v' and passes its results into output iterator 'out', returns 'out" after all
template <std::input_or_output_iterator Out>
constexpr Out visit_copy_all (visitor_for<Ts...> auto && v, Out out);
// passes all values into 'out' iterator, returns 'out' after all
template <std::input_or_output_iterator Out>
constexpr Out visit_copy_all (Out out);
// ...also const versions for visit...
};
ตัวอย่าง:
aa::variant_swarm< int , double , std::string> f;
// no runtime dispatching here, its just overloads
f.inesrt( " hello world " );
f.insert( 5 );
f.insert( 3.14 );
auto visitor = []( auto && x) {
std::cout << x << ' t ' ;
};
f.visit_all(visitor); // prints 5, 3.14, "hello world"
data_parallel_vector
คอนเทนเนอร์นี้ทำงานเป็น std::vector<T>
แต่เก็บฟิลด์แยกกัน
การดำเนินการที่รองรับ: view<T>
/ view<I>
เพื่อรับการขยายไปยังทุกฟิลด์ของดัชนีนี้
T
ต้องเป็นประเภทรวมหรือคล้ายทูเพิล
หมายเหตุ: data_parallel_vector
เป็นช่วงการเข้าถึงแบบสุ่ม หมายเหตุ: ละเว้นความเชี่ยวชาญพิเศษ std::vector<bool>
โดยจะทำงานเหมือนเวกเตอร์ปกติสำหรับบูล
template < typename T, typename Alloc>
struct data_parallel_vector {
using value_type = T;
using allocator_type = Alloc;
using difference_type = std:: ptrdiff_t ;
using size_type = std:: size_t ;
using reference = proxy; // similar to vector<bool>::reference type
using const_reference = const_proxy;
void swap (data_parallel_vector&) noexcept ;
friend void swap (data_parallel_vector&) noexcept ;
data_parallel_vector () = default ;
explicit data_parallel_vector ( const allocator_type& alloc);
data_parallel_vector (size_type count, const value_type& value,
const allocator_type& alloc = allocator_type());
explicit data_parallel_vector (size_type count, const allocator_type& alloc = allocator_type());
template <std::input_iterator It>
data_parallel_vector (It first, It last, const allocator_type& alloc = allocator_type());
data_parallel_vector ( const data_parallel_vector& other, const allocator_type& alloc);
data_parallel_vector (data_parallel_vector&& other, const allocator_type& alloc);
data_parallel_vector (std::initializer_list<value_type> init,
const allocator_type& alloc = allocator_type());
// copy-move all default
data_parallel_vector& operator =(std::initializer_list<T> ilist);
using iterator;
using const_iterator;
iterator begin ();
const_iterator begin () const ;
iterator end ();
const_iterator end () const ;
const_iterator cbegin () const ;
const_iterator cend () const ;
reference front ();
const_reference front () const ;
reference back ();
reference back () const ;
reference operator [](size_type pos);
const_reference operator [](size_type pos) const ;
size_type capacity () const ;
size_type max_size () const ;
// returns tuple of spans to underlying containers
template < typename ... Types>
auto view ();
template < typename ... Types>
auto view () const ;
template <std:: size_t ... Nbs>
auto view ();
template <std:: size_t ... Nbs>
auto view () const ;
bool empty () const ;
size_type size () const ;
bool operator ==( const data_parallel_impl&) const = default ;
iterator emplace (const_iterator pos, element_t <Is>... fields);
reference emplace_back ( element_t <Is>... fields);
void push_back ( const value_type& v);
void push_back (value_type&& v);
iterator erase (const_iterator pos);
iterator erase (const_iterator b, const_iterator e);
iterator insert (const_iterator pos, const value_type& value);
iterator insert (const_iterator pos, value_type&& value);
iterator insert (const_iterator pos, size_type count, const T& value);
template <std::input_iterator It>
iterator insert (const_iterator pos, It first, It last);
iterator insert (const_iterator pos, std::initializer_list<value_type> ilist);
void assign (size_type count, const value_type& value);
template <std::input_iterator It>
void assign (It first, It last);
void assign (std::initializer_list<T> ilist);
void clear ();
void pop_back ();
void reserve (size_type new_cap);
void resize (size_type sz);
void resize (size_type sz, const value_type& v);
void shrink_to_fit ();
};
ตัวอย่าง:
struct my_type {
int x;
float y;
bool l;
};
void foo () {
aa::data_parallel_vector<my_type> magic;
// ints, floats, bools are spans to all stored fields of my_type (&::x, &::y, &::l)
auto [ints, floats, bools] = magic;
magic. emplace_back ( 5 , 6 . f , true );
};
ดึงเนื้อหา:
include (FetchContent)
FetchContent_Declare(
AnyAny
GIT_REPOSITORY https://github.com/kelbon/AnyAny
GIT_TAG origin/main
)
FetchContent_MakeAvailable(AnyAny)
target_link_libraries (MyTargetName anyanylib)
add_subdirectory (AnyAny)
target_link_libraries (MyTargetName PUBLIC anyanylib)
build
git clone https://github.com/kelbon/AnyAny
cd AnyAny
cmake . -B build
cmake --build build
git clone https://github.com/kelbon/AnyAny
cd AnyAny/examples
cmake . -B build