Ý nghĩa của mã thông báo “……” là gì? tức là toán tử dấu chấm lửng kép trên gói tham số


110

Trong khi duyệt qua việc triển khai tiêu đề C ++ 11 mới hiện tại của gcc, tôi tình cờ gặp mã thông báo "......". Bạn có thể kiểm tra xem đoạn mã sau có biên dịch tốt không [qua ideone.com].

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

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

Vậy, ý nghĩa của mã thông báo này là gì?

chỉnh sửa: Có vẻ như SO đã cắt "......" trong tiêu đề câu hỏi thành "...", ý tôi thực sự là "......". :)


gợi ý: nó được ...theo sau bởi ....
Alexandre C.

5
Nó không giống như U...theo sau bởi .... Tuy nhiên, rất kỳ quặc.
edA-qa mort-ora-y

1
Lưu ý: Điều này có thể được tìm thấy trong <functional><type_traits>, luôn luôn trong ngữ cảnh của danh sách đối số hàm bên trong tham số mẫu.
Potatoswatter

cách duy nhất tôi tìm thấy để làm cho nó bị kẹt trong tiêu đề là đặt một khoảng trống ở giữa ... hy vọng nó làm cho nó rõ ràng hơn cho người đọc.
Matthieu M.

@Matthieu M.: Cảm ơn, tốt hơn nhiều!
Vitus

Câu trả lời:


79

Mọi trường hợp của sự kỳ lạ đó được ghép nối với một trường hợp của một dấu chấm lửng đơn thông thường.

  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; };

Tôi đoán rằng dấu chấm lửng kép có ý nghĩa tương tự với _ArgTypes..., ..., tức là một mở rộng mẫu đa dạng theo sau là danh sách các varargs kiểu C.

Đây là một bài kiểm tra hỗ trợ lý thuyết đó… Tôi nghĩ chúng ta có một người chiến thắng mới cho toán tử giả tồi nhất từ ​​trước đến nay.

Chỉnh sửa: Điều này có vẻ là phù hợp. §8.3.5 / 3 mô tả một cách để tạo danh sách tham số là

tham số-khai báo-danh sách lựa chọn ... lựa chọn

Vì vậy, dấu ba chấm kép được hình thành bởi một danh sách khai báo tham số kết thúc bằng một gói tham số, theo sau là một dấu chấm lửng khác.

Dấu phẩy hoàn toàn là tùy chọn; §8.3.5 / 4 không nói

Nếu đúng về mặt cú pháp và “...” không phải là một phần của bộ khai báo trừu tượng, thì “, ...” đồng nghĩa với “...”.

Đây bên trong một bộ khai báo trừu tượng, [sửa] nhưng Johannes nói rõ rằng họ đang đề cập đến một bộ khai báo trừu tượng trong một khai báo tham số. Tôi tự hỏi tại sao họ không nói "một phần của khai báo tham số" và tại sao câu đó không chỉ là một ghi chú thông tin…

Hơn nữa, va_begin()trong <cstdarg>yêu cầu một tham số trước danh sách varargs, vì vậy nguyên mẫu f(...)được C ++ cho phép cụ thể là vô dụng. Tham chiếu chéo với C99, nó là bất hợp pháp ở đồng bằng C. Vì vậy, điều này là kỳ lạ nhất.

Chú thích sử dụng

Theo yêu cầu, đây là minh họa về dấu chấm lửng kép:

#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 );
}

Vâng đúng vậy. T (U ..., ...) tuy nhiên cũng biên dịch tốt; có lẽ họ muốn tiết kiệm một số không gian. :)
Vitus

1
Nhưng điều đó có nghĩa là gì? Và làm thế nào trình biên dịch có thể cho biết _ArgTypes kết thúc ở đâu và một số tham số "bổ sung" bắt đầu?
Bo Persson

12
@Bo Persson: std::is_function's valuephải đúng ngay cả khi hàm là C varargs một và vì T (U ...) không phù hợp với hàm như vậy, bạn cần sự điên rồ này. Ví dụ: int f (int, char, ...) khớp chính xác T (U ......) với T = int, U = {int, char} và mã thông báo varargs "...".
Vitus

4
"Đây trong một bản tóm tắt-declarator" -> họ không có nghĩa là một phần của declarator trừu tượng của tham số cuối cùng của cùng một danh sách kiểu tham số. Ví dụ: void (int...)ở đây, ...không phải là một phần của bộ khai báo trừu tượng int, do đó nó đồng nghĩa với void(int, ...). Nếu bạn viết void(T...)Tlà một gói tham số mẫu, ...sẽ là một phần của bộ khai báo trừu tượng, và do đó nó sẽ không tương đương với void(T, ...).
Johannes Schaub - litb

2
"Hơn nữa, va_begin () trong <cstdarg> yêu cầu một tham số trước danh sách varargs, vì vậy nguyên mẫu f (...) được C ++ cho phép cụ thể là vô dụng." - Chỉ vô ích nếu bạn muốn biết những lập luận nào đã được thông qua. f(...)được sử dụng nhiều như một hàm dự phòng quá tải trong lập trình siêu mẫu, trong đó thông tin này là không cần thiết (và nơi hàm thậm chí không thực sự được gọi).

4

trên vs2015 phân tách dấu phẩy là điều cần thiết trong phiên bản mẫu:

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

một ví dụ thuyết minh là:

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

trân trọng, FM.


Tôi cũng nhận thấy điều này, nó vẫn xảy ra. Báo cáo lỗi tại developercommunity.visualstudio.com/content/problem/437260/… .
egyik

Tốt để biết. Bất kỳ tài liệu tham khảo hoặc trích dẫn nào cho quan điểm về điều này?
Màu đỏ. Lưu

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

Đây là một diễn đàn công cộng. Hãy để mọi người đọc những gì bạn nghĩ. PLZ giữ ngôn ngữ bản địa cho các tin nhắn riêng tư. سپاس.
Red.Wave

Được rồi. Tôi không phải là chuyên gia về tiêu chuẩn - tôi nghĩ rằng những người khác đã đề cập đến nó ở một số chi tiết ở trên. Nếu bất kỳ ai quan tâm đến nhận xét về báo cáo sự cố của Microsoft thì họ có thể nâng cao mức độ ưu tiên của nó. Báo cáo cho thấy tiếng kêu và gcc cho phép những gì VC ++ không cho phép vì vậy tôi nghĩ rằng chúng ta có thể đang ở trên một nền tảng khá vững chắc.
egyik
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.