เหตุใดการตรวจสอบแนวคิด Same_as จึงพิมพ์ความเท่าเทียมกันสองครั้ง


19

ดูที่การนำไปปฏิบัติที่เป็นไปได้ของแนวคิด same_as ที่https://en.cppreference.com/w/cpp/concepts/same_asฉันสังเกตเห็นว่ามีบางสิ่งแปลก ๆ เกิดขึ้น

namespace detail {
    template< class T, class U >
    concept SameHelper = std::is_same_v<T, U>;
}

template< class T, class U >
concept same_as = detail::SameHelper<T, U> && detail::SameHelper<U, T>;

คำถามแรกคือทำไมSameHelperแนวคิดจึงฝังอยู่? ประการที่สองคือทำไมsame_asการตรวจสอบถ้าTเป็นเช่นเดียวกับUและUเช่นเดียวกับT? ไม่ซ้ำซ้อนหรือไม่


เพียงเพราะSameHelper<T, U>อาจเป็นจริงไม่ได้หมายความว่าSameHelper<U, T>อาจจะเป็น
โปรแกรมเมอร์บางคนเพื่อน

1
นั่นคือประเด็นถ้า a เท่ากับ b, b เท่ากับ a ไม่ใช่หรือ?
user7769147

@ user7769147 ใช่แล้วนี่เป็นการกำหนดความสัมพันธ์นั้น
François Andrieux

4
อืมเอกสารสำหรับstd :: is_sameยังบอกอีกว่า "การแลกเปลี่ยนเป็นไปตามที่พอใจนั่นคือสำหรับ T และ U สองประเภทis_same<T, U>::value == trueถ้าหากว่าis_same<U, T>::value == true" นี่ก็หมายความว่าการตรวจสอบซ้ำนี้ไม่จำเป็น
เควิน

1
ไม่ผิดนี่คือ std :: is_same พูดว่า: หากเงื่อนไขนั้นมีอยู่สองประเภทจะสลับกัน ไม่จำเป็นต้องเป็นเช่นนั้น แต่ฉันไม่พบตัวอย่างของสองประเภทที่ไม่สลับกัน
Nemanja Boric

คำตอบ:


16

คำถามที่น่าสนใจ เมื่อเร็ว ๆ นี้ฉันได้ดูการพูดคุยของแนวคิดของ Andrew Sutton และในช่วงถาม - ตอบมีคนถามคำถามต่อไปนี้ (เวลาประทับในลิงค์ต่อไปนี้): CppCon 2018: Andrew Sutton "แนวคิดใน 60: ทุกสิ่งที่คุณจำเป็นต้องรู้

ดังนั้นคำถามเดือดลงไป: If I have a concept that says A && B && C, another says C && B && A, would those be equivalent?แอนดรูตอบว่าใช่ แต่ชี้ให้เห็นความจริงที่คอมไพเลอร์มีวิธีการบางอย่างภายใน (ที่มีความโปร่งใสให้กับผู้ใช้) ในการย่อยสลายแนวคิดเข้าไปในข้อเสนอตรรกะอะตอม ( atomic constraintsแอนดรูถ้อยคำระยะ) และการตรวจสอบไม่ว่าจะเป็น เท่ากัน

ตอนนี้ดูสิ่งที่ cppreference พูดเกี่ยวกับstd::same_as:

std::same_as<T, U>subsumes std::same_as<U, T>และในทางกลับกัน

มันเป็นพื้นสัมพันธ์ "if-and-only-if" พวกเขาหมายถึงกันและกัน (สมการเชิงตรรกะ)

การคาดเดาของฉันอยู่ที่นี่ จำกัด std::is_same_v<T, U>อะตอม วิธีที่คอมไพเลอร์ปฏิบัติstd::is_same_vอาจทำให้พวกเขาคิดstd::is_same_v<T, U>และstd::is_same_v<U, T>เป็นข้อ จำกัด ที่แตกต่างกันสองข้อ ดังนั้นหากคุณใช้งานstd::same_asโดยใช้หนึ่งในนั้น:

template< class T, class U >
concept same_as = detail::SameHelper<T, U>;

จากนั้นstd::same_as<T, U>และstd::same_as<U, T>จะ "ระเบิด" กับข้อ จำกัด ของอะตอมที่แตกต่างกันและจะไม่เทียบเท่ากัน

ทำไมคอมไพเลอร์จึงสนใจ?

ลองพิจารณาตัวอย่างนี้ :

#include <type_traits>
#include <iostream>
#include <concepts>

template< class T, class U >
concept SameHelper = std::is_same_v<T, U>;

template< class T, class U >
concept my_same_as = SameHelper<T, U>;

// template< class T, class U >
// concept my_same_as = SameHelper<T, U> && SameHelper<U, T>;

template< class T, class U> requires my_same_as<U, T>
void foo(T a, U b) {
    std::cout << "Not integral" << std::endl;
}

template< class T, class U> requires (my_same_as<T, U> && std::integral<T>)
void foo(T a, U b) {
    std::cout << "Integral" << std::endl;
}

int main() {
    foo(1, 2);
    return 0;
}

จะเป็นการดีที่my_same_as<T, U> && std::integral<T>subsumes my_same_as<U, T>; ดังนั้นคอมไพเลอร์ควรเลือกแม่แบบเชี่ยวชาญสองยกเว้น ... มันไม่ได้: error: call of overloaded 'foo(int, int)' is ambiguousคอมไพเลอร์จะส่งเสียงข้อผิดพลาด

เหตุผลที่อยู่เบื้องหลังคือเนื่องจากmy_same_as<U, T>และmy_same_as<T, U>ไม่ได้รวมกันmy_same_as<T, U> && std::integral<T>และmy_same_as<U, T>กลายเป็นที่เปรียบมิได้

อย่างไรก็ตามหากคุณเปลี่ยน

template< class T, class U >
concept my_same_as = SameHelper<T, U>;

กับ

template< class T, class U >
concept my_same_as = SameHelper<T, U> && SameHelper<U, T>;

รหัสรวบรวม


same_as <T, U> และ same_as <U, T> อาจเป็นข้อ จำกัด ของอะตอมที่แตกต่างกัน แต่ผลลัพธ์ของพวกเขาจะยังคงเหมือนเดิม ทำไมคอมไพเลอร์ใส่ใจอย่างมากกับการนิยาม Same_as ให้เป็นข้อ จำกัด ของอะตอมสองข้อที่แตกต่างกันซึ่งจากมุมมองเชิงตรรกะเหมือนกัน?
user7769147

2
คอมไพเลอร์จำเป็นต้องพิจารณานิพจน์สองใด ๆที่แตกต่างกันสำหรับการ จำกัด การ จำกัด แต่สามารถพิจารณาการขัดแย้งกับพวกเขาในแบบที่ชัดเจน ดังนั้นไม่เพียง แต่เราจะต้องได้ทั้งสองทิศทาง (เพื่อให้มันไม่สำคัญที่พวกเขากำลังสั่งซื้อชื่อเมื่อเปรียบเทียบ จำกัด ) เรายังต้องSameHelper: มันทำให้ทั้งสองใช้ของis_same_vเป็นผลมาจากการแสดงออกเดียวกัน
Davis Herring

@ user7769147 ดูคำตอบที่ปรับปรุงแล้ว
Rin Kaenbyou

1
ดูเหมือนว่าภูมิปัญญาดั้งเดิมนั้นผิดเกี่ยวกับความเสมอภาคของแนวคิด ซึ่งแตกต่างจากแม่แบบที่is_same<T, U>เหมือนกันis_same<U, T>ข้อ จำกัด ของอะตอมสองข้อไม่ถือว่าเหมือนกันเว้นแต่ว่ามันจะถูกสร้างขึ้นจากนิพจน์เดียวกัน ดังนั้นความต้องการสำหรับทั้งสอง
AndyG

เกี่ยวกับare_same_asอะไร template<typename T, typename U0, typename... Un> concept are_same_as = SameAs<T, U0> && (SameAs<T, Un> && ...);จะล้มเหลวในบางกรณี ตัวอย่างเช่นare_same_as<T, U, int>จะเทียบเท่าare_same_as<T, int, U>แต่ไม่ถึงare_same_as<U, T, int>
user7769147

2

std::is_same ถูกกำหนดให้เป็นจริงถ้าหากว่า:

T และ U ตั้งชื่อประเภทเดียวกันที่มีคุณสมบัติ CV เดียวกัน

เท่าที่ฉันรู้มาตรฐานไม่ได้นิยามความหมายของ "ประเภทเดียวกัน" แต่ในภาษาธรรมชาติและตรรกะ "เดียวกัน" นั้นมีความสัมพันธ์เชิงสมมูล

จากข้อสันนิษฐานนี้ซึ่งฉันได้กำหนดis_same_v<T, U> && is_same_v<U, V>ไว้ แต่same_­asไม่ได้ระบุไว้ในเงื่อนไขของis_same_v; นั่นเป็นเพียงสำหรับการแสดงออก

การตรวจสอบอย่างชัดเจนสำหรับทั้งสองอนุญาตให้ใช้งานสำหรับsame-as-implการตอบสนองsame_­asโดยไม่ต้องสลับ การระบุวิธีนี้จะอธิบายลักษณะการทำงานของแนวคิดโดยไม่ จำกัด ว่าจะนำไปปฏิบัติอย่างไร

ทำไมฉันเลือกวิธีนี้แทนการระบุในแง่ของis_same_vฉันไม่รู้ ข้อได้เปรียบของวิธีการที่เลือกนั้นอาจเป็นได้ว่าคำจำกัดความทั้งสองนั้นเป็นแบบแยกกัน หนึ่งไม่ขึ้นอยู่กับอื่น ๆ


2
ฉันเห็นด้วยกับคุณ แต่การโต้แย้งครั้งสุดท้ายนี้ยืดออกไปเล็กน้อย สำหรับฉันดูเหมือนว่า: "เฮ้ฉันมีส่วนประกอบที่นำกลับมาใช้ใหม่ได้ซึ่งบอกฉันว่าทั้งสองประเภทเหมือนกันตอนนี้ฉันมีส่วนประกอบอื่นที่ต้องการทราบว่าประเภทนั้นเหมือนกันหรือไม่ ฉันจะสร้างโซลูชัน ad-hoc เฉพาะกรณีนี้ตอนนี้ฉัน 'แยกชิ้น' คนที่ต้องการคำจำกัดความของความเท่าเทียมจากผู้ชายที่มีคำจำกัดความของความเท่าเทียม Yay! "
Cássio Renan

1
@ CássioRenan Sure อย่างที่ฉันพูดฉันไม่รู้ว่าทำไมนั่นเป็นเหตุผลที่ดีที่สุดที่ฉันจะได้รับ ผู้เขียนอาจมีเหตุผลที่ดีกว่า
eerorika
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.