เสียงดังกราว / gcc ในความเชี่ยวชาญเฉพาะทางของชั้นเรียน


9

ฉันเจอปัญหานี้ในขณะที่พยายามชำนาญtuple_size/ tuple_elementสำหรับคลาสที่กำหนดเองใน C ++ 17 สำหรับการโยงโครงสร้าง

โค้ดด้านล่างรวบรวมใน GCC แต่ไม่ใช่ในเสียงดังกราว (ทั้งรุ่นลำตัวดูที่ลิงค์ด้านล่าง)

#include <type_traits>

template<typename T, typename... Ts>
using sfinae_t = T;

template<typename T, bool... Bs>
using sfinae_v_t = sfinae_t<T, typename std::enable_if<Bs>::type...>;

template <typename T>
struct Test;

template <typename T>
struct Test<sfinae_v_t<T, std::is_integral_v<T>>> {};

void f() {
    Test<int> t;
}

https://godbolt.org/z/ztuRSq

นี่คือข้อผิดพลาดที่จัดทำโดยเสียงดังกราว:

<source>:13:8: error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list

struct Test<sfinae_v_t<T, std::is_integral<T>::value>> {};

       ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1 error generated.

Compiler returned: 1

นี่เป็นข้อผิดพลาดในคอมไพเลอร์หรือว่าโค้ดด้านบนเรียกใช้ UB บางตัวหรือไม่


3
นี้ได้ง่ายมากยิ่งขึ้น
Evg

3
ICC และ MSVC ไม่สามารถคอมไพล์ได้เช่นกัน
ChrisMM

@Evg มันน่าแปลกใจที่gccคอมไพล์ที่เห็นเป็นมันไม่ได้รวบรวมนี้ ...
แม็กซ์ Langhof

1
FWIW สิ่งนี้ควรมีรูปแบบไม่ดีหากฉันไม่ได้เข้าใจผิดอย่างสมบูรณ์ (ด้วยเหตุผลเดียวกับที่สิ่งนี้ไม่ได้เป็นจริง)
Max Langhof

1
เนื่องจากเราอ้างถึงมาตรฐานฉันจึงเพิ่มแท็กทนายความภาษา
Guillaume Racicot

คำตอบ:


3

สิ่งที่ฉันบอกด้านล่าง (ภายใต้OLD POST ) ควรเป็นจริงในระดับหนึ่ง แต่ปัญหาที่แท้จริงของสิ่งนี้คือ SFINAE ถูกใช้อย่างไม่ถูกต้องดังนั้นฉันจึงไม่แน่ใจอีกต่อไปว่านี่เป็นข้อผิดพลาดใน gcc

การประกาศนามแฝงจะต้องประสบความสำเร็จเสมอคุณไม่สามารถ SFINAE ที่นั่นได้เนื่องจากไม่ใช่การประกาศคลาสหรือฟังก์ชั่นหรือความเชี่ยวชาญพิเศษ (ที่เหมาะสมเนื่องจากคุณไม่สามารถใช้นามแฝงได้) หากการประกาศสมนามไม่ประสบความสำเร็จ programm จะเกิดขึ้นไม่ถูกต้อง ดังนั้นคอมไพเลอร์อาจคิดว่ามันจะไม่เกิดขึ้นในกรณีที่การประกาศนามแฝงไม่สำเร็จจนกว่าคุณจะบังคับให้มันสร้างอินสแตนซ์ของเทมเพลตดังกล่าว

ดังนั้นจึงเป็นที่ยอมรับได้อย่างสมบูรณ์สำหรับคอมไพเลอร์ที่จะคิดsfinae_v_t<T,...>เสมอTว่ามันจะเกิดขึ้นเมื่อโปรแกรมไม่ได้เกิดขึ้น ดังนั้นจะเห็นได้ว่าในทุกกรณีที่โปรแกรมไม่ได้ถูกจัดรูปแบบขึ้นมาความเชี่ยวชาญเฉพาะทางบางส่วนนั้นไม่เชี่ยวชาญและจะบอกคุณว่านี่เป็นรูปแบบที่ไม่ดี (นั่นคือสิ่งที่เสียงดังกราวทำ)

ฉันไม่คิดว่าคอมไพเลอร์ถูกบังคับให้ทำเช่นนี้ และถ้ามันไม่ได้และเพียงแค่คิดว่า "ตกลงsfinae_v_tเป็นบางประเภทอะไรก็ตาม" แล้วมันก็ไม่ชัดเจนว่านี่คือการประกาศใหม่ ดังนั้นฉันคิดว่าจนกว่าเราจะยกตัวอย่างหนึ่งในนั้นไม่มีอะไรผิดปกติที่ไม่ทิ้งข้อผิดพลาด

แต่เมื่อเรายกตัวอย่างมันควรจะมีปัญหาที่เรามีการประกาศซ้ำหรือโปรแกรมนั้นมีรูปแบบไม่ดีเนื่องจากstd::enable_ifขึ้นอยู่กับอาร์กิวเมนต์ของแม่แบบ GCC ควรเลือกอย่างน้อยหนึ่งรายการ แต่ไม่ทำ

std::enable_ifนอกจากนี้ยังไม่แน่นอนไม่ได้นำไปใช้กับตัวอย่างที่ง่ายขึ้นโดยไม่ต้อง ดังนั้นฉันจึงยังคิดว่านี่เป็นข้อผิดพลาดใน GCC แต่ฉันก็พอเข้าใจแล้วว่าฉันไม่สามารถพูดได้อย่างแน่นอนอีกต่อไป ฉันแค่จะบอกว่าบางคนควรรายงานว่าเป็นข้อผิดพลาดและให้ผู้คนจาก gcc คิดเกี่ยวกับมัน

โพสต์เก่า

นี่เป็นข้อผิดพลาดใน gcc มาตรฐานให้กฎแก่เราในการแปลงแม่แบบชั้นเรียนในแม่แบบฟังก์ชัน เทมเพลตคลาสหนึ่งมีความเชี่ยวชาญมากกว่าแบบอื่นหากฟังก์ชันมาก่อนเทมเพลตอื่นในการสั่งซื้อเทมเพลตบางส่วน

ฉันสร้างฟังก์ชั่นที่นี่และตอนนี้ gcc อ้างว่าการเรียกพวกมันนั้นคลุมเครือดังนั้นมันก็ต้องบอกว่าเทมเพลตของคลาสนั้นถูกระบุอย่างเท่าเทียมกัน

หมายเหตุ: การอ่านมาตรฐานอย่างละเอียดผู้แปลในหัวของฉันเห็นด้วยกับเสียงดังกราว


เป็นsfinae_v_t<T, std::is_integral_v<T>>และsfinae_v_t<T, !std::is_integral_v<T>>ได้รับการปฏิบัติเหมือนกันหรือไม่? ความหมายพวกเขาไม่ได้
ofo

@ GuillaumeRacicot ค่อนข้างเป็นไปได้ แต่ฉันต้องการที่จะเข้าใจว่าทำไม ตัวอย่างเช่นมาตรฐานยังระบุว่า "ไม่สามารถตรวจสอบชื่อที่ขึ้นอยู่กับเมื่อประกาศความเชี่ยวชาญเฉพาะบางส่วน แต่จะถูกตรวจสอบเมื่อแทนที่ลงในความเชี่ยวชาญบางส่วน" นั่นหมายความว่าไม่ว่าพวกเขาจะเป็นประเภทเดียวกันหรือไม่จะต้องตัดสินใจหลังจากการแทนที่ T ในความเชี่ยวชาญบางส่วนตั้งแต่sfinae_v_t<T>ขึ้นอยู่กับT? ในกรณีนี้พวกเขาจะไม่เหมือนกันเพราะจะมีรูปแบบไม่ดี
ofo

@ofo ฉันต้องบอกว่าฉันไม่แน่ใจ enable_if_tมันเป็นบิตของยียวนที่จะได้คิดเกี่ยวกับทั้งสองตั้งแต่หนึ่งของพวกเขาจะไม่เป็นชนิดและใช้พวกเขาทั้งสองในบริบทที่ไม่ใช่แม่จะส่งผลในการรวบรวมข้อผิดพลาดเนื่องจากการ การอ่านมาตรฐานที่ดีที่สุดของฉันคือมันไม่สำคัญว่าจะเหมือนกันหรือไม่ สำหรับการสั่งซื้อบางส่วนเรามักจะเปรียบเทียบรูปแบบพารามิเตอร์ templare ของหนึ่งฟังก์ชั่นกับรูปแบบอาร์กิวเมนต์เทมเพลตของอีกคนหนึ่ง (เช่นintถูกแทนที่แล้ว) และจากนั้นมีประเภทที่แท้จริงในหนึ่งของพวกเขาดังนั้นเราจึงไม่ต้องเปรียบเทียบ พวกเขาเป็นนามธรรม
n314159

1
ขุดลึกลงไปผมพบนี้มาจากที่นี่ SFINAE ควรทำงานได้ดีกับนามแฝงแม่แบบมิฉะนั้นtemplate<bool B, typename T> enable_if_t = typename enable_if<B, T>::type;จะไม่ทำงานเช่นกัน ฉันจะไปข้างหน้าและยื่นข้อผิดพลาดกับ gcc แต่ไม่แน่ใจว่าหาก gcc ผิดที่นั่น ขอบคุณ
ofo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.