โทเค็น“ ……” มีความหมายว่าอย่างไร? คือตัวดำเนินการจุดไข่ปลาคู่บนชุดพารามิเตอร์


110

ในขณะที่เรียกดูการใช้งานส่วนหัว C ++ 11 ใหม่ในปัจจุบันของ gcc ฉันพบโทเค็น "...... " คุณสามารถตรวจสอบได้ว่าโค้ดต่อไปนี้คอมไพล์ดี [ผ่าน ideone.com]

template <typename T>
struct X
{ /* ... */ };

template <typename T, typename ... U>
struct X<T(U......)> // this line is the important one
{ /* ... */ };

ความหมายของโทเค็นนี้คืออะไร?

แก้ไข: ดูเหมือนว่า SO ถูกตัด "...... " ในชื่อคำถามเป็น "... " ฉันหมายถึง "...... " จริงๆ :)


คำแนะนำ: มันจะตามมาด้วย... ...
Alexandre C.

5
มันไม่ได้มากขึ้นเช่นตามมาด้วยU... ...แปลกมาก
edA-qa mort-ora-y

1
หมายเหตุ: สิ่งนี้สามารถพบได้ใน<functional>และ<type_traits>เสมอในบริบทของรายการอาร์กิวเมนต์ของฟังก์ชันภายในพารามิเตอร์เทมเพลต
Potatoswatter

วิธีเดียวที่ฉันพบว่าทำให้มันติดอยู่ในชื่อเรื่องคือการเว้นวรรคระหว่าง ... หวังว่ามันจะชัดเจนสำหรับผู้อ่าน
Matthieu M.

@ Matthieu M: ขอบคุณมากดีกว่า!
Vitus

คำตอบ:


79

ทุกอินสแตนซ์ของความแปลกนั้นจับคู่กับกรณีของจุดไข่ปลาปกติ

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...)>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......)>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...) const>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......) const>
    { typedef _Res result_type; };

ฉันเดาว่าจุดไข่ปลาคู่มีความหมายใกล้เคียงกัน_ArgTypes..., ...นั่นคือการขยายเทมเพลตแบบแปรผันตามด้วยรายการ varargs สไตล์ C

นี่คือการทดสอบที่สนับสนุนทฤษฎีนั้น ... ฉันคิดว่าเรามีผู้ชนะรายใหม่สำหรับตัวดำเนินการหลอกที่แย่ที่สุดเท่าที่เคยมีมา

แก้ไข:สิ่งนี้ดูเหมือนจะสอดคล้องกัน §8.3.5 / 3 อธิบายวิธีหนึ่งในการสร้างรายการพารามิเตอร์เป็น

พารามิเตอร์-Declaration-list opt ... opt

ดังนั้นจุดไข่ปลาสองชั้นจึงถูกสร้างขึ้นโดยรายการการประกาศพารามิเตอร์ที่ลงท้ายด้วยแพ็กพารามิเตอร์ตามด้วยจุดไข่ปลาอื่น

เครื่องหมายจุลภาคเป็นทางเลือกเท่านั้น §8.3.5 / 4 พูด

ในกรณีที่ถูกต้องตามหลักไวยากรณ์และโดยที่“ ... ” ไม่ได้เป็นส่วนหนึ่งของผู้ประกาศนามธรรม“, ... ” มีความหมายเหมือนกับ“ ... ”

สิ่งนี้อยู่ใน abstract-declarator [แก้ไข]แต่ Johannes ได้ชี้ให้เห็นว่าพวกเขากำลังอ้างถึง abstract-declarator ภายในการประกาศพารามิเตอร์ ฉันสงสัยว่าทำไมพวกเขาถึงไม่พูดว่า "เป็นส่วนหนึ่งของการประกาศพารามิเตอร์" และเหตุใดประโยคนั้นจึงไม่เป็นเพียงบันทึกข้อมูล ...

นอกจากนี้va_begin()ใน<cstdarg>ต้องการพารามิเตอร์ก่อนรายการ varargs ดังนั้นต้นแบบที่f(...)C ++ อนุญาตโดยเฉพาะจึงไม่มีประโยชน์ การอ้างอิงโยงกับ C99 ถือเป็นเรื่องผิดกฎหมายในภาษา C ธรรมดาดังนั้นนี่จึงเป็นเรื่องแปลกประหลาดที่สุด

หมายเหตุการใช้งาน

ตามคำขอนี่คือการสาธิตของจุดไข่ปลาคู่:

#include <cstdio>
#include <string>

template< typename T >
T const &printf_helper( T const &x )
    { return x; }

char const *printf_helper( std::string const &x )
    { return x.c_str(); }

template< typename ... Req, typename ... Given >
int wrap_printf( int (*fn)( Req... ... ), Given ... args ) {
    return fn( printf_helper( args ) ... );
}

int main() {
    wrap_printf( &std::printf, "Hello %s\n", std::string( "world!" ) );
    wrap_printf( &std::fprintf, stderr, std::string( "Error %d" ), 5 );
}

ใช่มันเป็นสิ่งที่ถูก. T (U ... , ... ) แต่รวบรวมได้ดีด้วย; บางทีพวกเขาอาจต้องการประหยัดพื้นที่ :)
Vitus

1
แต่นั่นจะหมายความว่าอย่างไร? แล้วคอมไพเลอร์จะบอกได้อย่างไรว่า _ArgTypes สิ้นสุดที่ใดและพารามิเตอร์ "extra" เริ่มต้นอย่างไร
Bo Persson

12
@Bo เพอร์สัน: std::is_function's valueต้องเป็นจริงแม้ว่าฟังก์ชั่นคือ C varargs หนึ่งและเนื่องจาก T (U ... ) จะไม่ตรงกับฟังก์ชั่นเช่นนี้คุณต้องบ้านี้ เช่น int f (int, char, ... ) ตรงกับ T (U ...... ) ตรงกับ T = int, U = {int, char} และโทเค็น varargs "... "
Vitus

4
"สิ่งนี้อยู่ใน abstract-declarator" -> หมายความว่าไม่ได้เป็นส่วนหนึ่งของผู้ประกาศนามธรรมของพารามิเตอร์สุดท้ายของรายการประเภทพารามิเตอร์เดียวกันนั้น เช่นvoid (int...)ที่นี่...ไม่ได้เป็นส่วนหนึ่งของนามธรรม declarator จึงมีความหมายไปint void(int, ...)ถ้าคุณจะเขียนvoid(T...)และTเป็นชุดแม่แบบพารามิเตอร์...จะเป็นส่วนหนึ่งของนามธรรม declarator void(T, ...)และด้วยเหตุนี้มันจะไม่เทียบเท่ากับ
Johannes Schaub - litb

2
"นอกจากนี้ va_begin () ใน <cstdarg> ต้องการพารามิเตอร์ก่อนรายการ varargs ดังนั้นต้นแบบ f (... ) ที่ C ++ อนุญาตโดยเฉพาะจึงไม่มีประโยชน์" - ไม่มีประโยชน์หากคุณต้องการทราบว่ามีการโต้แย้งอะไรบ้าง f(...)ถูกใช้อย่างหนักในฐานะฟังก์ชันทางเลือกที่เกินพิกัดในการเขียนโปรแกรมแม่แบบโดยที่ข้อมูลนี้ไม่จำเป็น (และในกรณีที่ฟังก์ชันไม่ได้รับการเรียกใช้จริง)

4

ใน vs2015 การคั่นด้วยจุลภาคเป็นสิ่งสำคัญในเวอร์ชันเทมเพลต:

    template <typename T, typename ... U>
    struct X<T(U...,...)> {};// this line is the important one

ตัวอย่างการสร้างอินสแตนซ์คือ:

    X<int(int...)> my_va_func;

ขอแสดงความนับถือ FM.


ฉันเพิ่งสังเกตเห็นสิ่งนี้เช่นกันมันยังคงเกิดขึ้น รายงานข้อผิดพลาดที่developercommunity.visualstudio.com/content/problem/437260/...
egyik

ดีแล้วที่รู้. การอ้างอิงหรือการอ้างอิงถึงมาตรฐานเกี่ยวกับเรื่องนี้หรือไม่?
Red.Wave

.سلامببخشیدنمیدانم
egyik

นี่คือเวทีสาธารณะ ให้คนอ่านคิดว่าอย่างไร PLZ ใช้ภาษาพื้นเมืองสำหรับข้อความส่วนตัว سپاس.
Red Wave

โอเคถ้าอย่างนั้น. ฉันไม่ใช่ผู้เชี่ยวชาญเกี่ยวกับมาตรฐาน - ฉันคิดว่าคนอื่นได้กล่าวถึงรายละเอียดข้างต้น หากใครสนใจที่จะแสดงความคิดเห็นเกี่ยวกับรายงานปัญหาของ Microsoft อาจเพิ่มความสำคัญ รายงานแสดงเสียงดังและ gcc อนุญาตสิ่งที่ VC ++ ไม่ได้ดังนั้นฉันคิดว่าเราน่าจะอยู่ในพื้นที่ที่ค่อนข้างแข็งแกร่ง
egyik
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.