ไม่memcmp
ไม่เหมาะที่จะทำเช่นนี้ และการไตร่ตรองใน C ++ นั้นไม่เพียงพอที่จะทำสิ่งนี้ ณ จุดนี้ (จะมีคอมไพเลอร์ทดลองที่สนับสนุนการสะท้อนที่แข็งแกร่งพอที่จะทำสิ่งนี้ได้แล้วและc ++ 23อาจมีคุณสมบัติที่คุณต้องการ)
วิธีที่ง่ายที่สุดในการแก้ปัญหาของคุณคือทำการสะท้อนด้วยตนเอง
รับสิ่งนี้:
struct some_struct {
int x;
double d1, d2;
char c;
};
เราต้องการทำงานน้อยที่สุดเพื่อให้เราสามารถเปรียบเทียบสองสิ่งนี้
ถ้าเรามี:
auto as_tie(some_struct const& s){
return std::tie( s.x, s.d1, s.d2, s.c );
}
หรือ
auto as_tie(some_struct const& s)
-> decltype(std::tie( s.x, s.d1, s.d2, s.c ))
{
return std::tie( s.x, s.d1, s.d2, s.c );
}
สำหรับc ++ 11จากนั้น:
template<class S>
bool are_equal( S const& lhs, S const& rhs ) {
return as_tie(lhs) == as_tie(rhs);
}
ทำผลงานได้ค่อนข้างดี
เราสามารถขยายกระบวนการนี้ให้ทำงานซ้ำได้ แทนที่จะเปรียบเทียบความสัมพันธ์ให้เปรียบเทียบแต่ละองค์ประกอบในเทมเพลตและเทมเพลตนั้นoperator==
ใช้กฎนี้ซ้ำ (ตัดองค์ประกอบในas_tie
การเปรียบเทียบ) ยกเว้นว่าองค์ประกอบนั้นมีการทำงานอยู่==
แล้วและจัดการอาร์เรย์
สิ่งนี้จะต้องมีไลบรารี่เล็กน้อย (โค้ด 100ish line?) พร้อมกับการเขียนข้อมูล "reflect" ของสมาชิกต่อสมาชิกเล็กน้อย หากจำนวนของ structs ที่คุณมี จำกัด มันอาจจะง่ายต่อการเขียนรหัสต่อโครงสร้างด้วยตนเอง
อาจมีวิธีที่จะได้รับ
REFLECT( some_struct, x, d1, d2, c )
เพื่อสร้างas_tie
โครงสร้างโดยใช้มาโครที่น่ากลัว แต่as_tie
ก็ง่ายพอสมควร ในc ++ 11การทำซ้ำนั้นน่ารำคาญ สิ่งนี้มีประโยชน์:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
ในสถานการณ์เช่นนี้และอื่น ๆ อีกมากมาย ด้วยRETURNS
การเขียนas_tie
คือ:
auto as_tie(some_struct const& s)
RETURNS( std::tie( s.x, s.d1, s.d2, s.c ) )
ลบการทำซ้ำ
นี่คือแทงที่ทำให้มันเกิดซ้ำ:
template<class T,
typename std::enable_if< !std::is_class<T>{}, bool>::type = true
>
auto refl_tie( T const& t )
RETURNS(std::tie(t))
template<class...Ts,
typename std::enable_if< (sizeof...(Ts) > 1), bool>::type = true
>
auto refl_tie( Ts const&... ts )
RETURNS(std::make_tuple(refl_tie(ts)...))
template<class T, std::size_t N>
auto refl_tie( T const(&t)[N] ) {
// lots of work in C++11 to support this case, todo.
// in C++17 I could just make a tie of each of the N elements of the array?
// in C++11 I might write a custom struct that supports an array
// reference/pointer of fixed size and implements =, ==, !=, <, etc.
}
struct foo {
int x;
};
struct bar {
foo f1, f2;
};
auto refl_tie( foo const& s )
RETURNS( refl_tie( s.x ) )
auto refl_tie( bar const& s )
RETURNS( refl_tie( s.f1, s.f2 ) )
c ++ 17 refl_tie (array) (เรียกซ้ำทั้งหมดแม้สนับสนุนอาร์เรย์ของอาร์เรย์):
template<class T, std::size_t N, std::size_t...Is>
auto array_refl( T const(&t)[N], std::index_sequence<Is...> )
RETURNS( std::array<decltype( refl_tie(t[0]) ), N>{ refl_tie( t[Is] )... } )
template<class T, std::size_t N>
auto refl_tie( T(&t)[N] )
RETURNS( array_refl( t, std::make_index_sequence<N>{} ) )
ตัวอย่างสด
นี่ผมใช้ของstd::array
refl_tie
นี้เร็วกว่า tuple ก่อนหน้าของฉันของ refl_tie ในเวลารวบรวม
ด้วย
template<class T,
typename std::enable_if< !std::is_class<T>{}, bool>::type = true
>
auto refl_tie( T const& t )
RETURNS(std::cref(t))
การใช้std::cref
ที่นี่แทนstd::tie
สามารถประหยัดค่าใช้จ่ายในการคอมไพล์เวลาเช่นเดียวกับcref
คลาสที่ง่ายกว่าtuple
มาก
ในที่สุดคุณควรเพิ่ม
template<class T, std::size_t N, class...Ts>
auto refl_tie( T(&t)[N], Ts&&... ) = delete;
ซึ่งจะป้องกันสมาชิกอาเรย์จากการเน่าเปื่อยไปยังพอยน์เตอร์และถอยกลับไปที่ตัวชี้ความเท่าเทียมกัน (ซึ่งคุณอาจไม่ต้องการจากอาร์เรย์)
หากปราศจากสิ่งนี้ถ้าคุณส่งอาร์เรย์ไปยังโครงสร้างที่ไม่มีการสะท้อนกลับมันจะกลับไปที่โครงสร้างของตัวชี้ไปยังที่ไม่ถูกสะท้อนrefl_tie
ซึ่งจะทำงานและส่งกลับเรื่องไร้สาระ
ด้วยสิ่งนี้คุณจะพบกับข้อผิดพลาดในการรวบรวมเวลา
การสนับสนุนการเรียกซ้ำผ่านไลบรารีชนิดนั้นเป็นเรื่องยุ่งยาก คุณทำได้std::tie
:
template<class T, class A>
auto refl_tie( std::vector<T, A> const& v )
RETURNS( std::tie(v) )
แต่นั่นไม่สนับสนุนการเรียกซ้ำผ่านมัน