2012-04-06 17 views
19

Tôi đã biết cách stdarg.h để có hàm có đối số biến trong C++ như đã thảo luận here chẳng hạn. Tôi cũng biết tiêu chuẩn C++ 11 có các mẫu variadic như được giải thích here.Một hàm có số biến đối số với các kiểu đã biết, cách C++ 11

Nhưng trong cả hai đề án nói trên, chúng tôi không biết (và chúng tôi không thể ép buộc) loại đối số trong thời gian biên dịch afaik. Những gì tôi đang tìm kiếm là chuyển đối số biến của các loại đã biết thành một hàm. Tôi nghĩ rằng điều này có thể được thực hiện bởi vì tôi đọc về nó here:

variadic mẫu, mà cũng có thể được sử dụng để tạo ra các chức năng mà phải mất số biến của tham số, thường là lựa chọn tốt hơn bởi vì họ không áp đặt các hạn chế trên các loại đối số, không thực hiện các chương trình khuyến mãi tích phân và dấu phẩy động và được nhập an toàn.

Có thể không? Nếu có, làm thế nào tôi có thể làm điều này?

Trả lời

30

Thật là thẳng về phía trước để viết một hàm với mẫu variadic, chấp nhận một số lượng đối số tùy ý. Sự khác biệt duy nhất đối với mẫu chung là, một kiểu cụ thể được sử dụng làm đối số đầu tiên (đầu) - thay vì tham số mẫu. Ví dụ sau đây cho thấy một hàm foobar, chấp nhận một số chuỗi tùy ý.

// used for end of recursion - and for the empty arguments list 
void foobar() { } 

template <typename ...Tail> 
void foobar(const std::string& head, Tail&&... tail) 
{ 
    // do something with head 
    std::cout << head << '\n'; 
    // call foobar recursively with remaining arguments 
    foobar(std::forward<Tail>(tail)...); 
} 

foobar("Hello", "World", "..."); 

Cá nhân, tôi thích sử dụng std::initializer_list thay vì mẫu variadic. Bởi vì các mẫu variadic phức tạp hơn và đòi hỏi thêm kinh nghiệm. Với std::initializer_list, nó có thể trông như thế này:

void foobar(std::initializer_list<std::string> values) 
{ 
    for (auto& value : values) { 
     // do something with value 
     std::cout << value << '\n'; 
    } 
} 

foobar({ "Hello", "World", "...", }); 

Thật không may, các dấu ngoặc nhọn thêm được yêu cầu khi sử dụng std::initializer_list với các chức năng thông thường. Chúng không bắt buộc đối với các nhà xây dựng, nếu cú ​​pháp khởi tạo mới được sử dụng.

Chỉnh sửa: Viết lại câu trả lời theo phản hồi. Đặc biệt tôi đã thay đổi thứ tự của hai giải pháp/ví dụ.

+1

Tôi nghĩ đó là tất cả về sự hiểu lầm của tôi. Tôi biết cách thứ hai, nhưng tôi luôn nghĩ rằng không có kiểm soát về loại tham số. Đây không phải là sự thật. bởi vì hàm lấy tham số đầu tiên của một kiểu đã biết (chuỗi ở đây), nó buộc phải có các tham số của kiểu đó. Cảm ơn bạn. – melmi

+2

Trước tiên, bạn có thể muốn di chuyển hộp mã thứ hai. Đó là một giải pháp rất tốt cho vấn đề, trong khi phiên bản 'initializer_list' thì không. Tôi sẽ đăng một điều lớn, phức tạp với SFINAE và như vậy, nhưng điều này là hợp lý hơn nhiều. –

+0

@ nosid bạn thực sự có thể tránh sử dụng dấu ngoặc nhọn nếu bạn trộn cả std :: initializer_list và phương pháp tiếp cận mẫu variadic, bằng cách tạo một wrapper mẫu variadic xung quanh phiên bản std :: initializer_list, như sau: [xem trên coliru] (http: //coliru.stacked-crooked.com/a/4baef67192a0310c). –

2

Nếu tham số biến là tất cả một loại, bạn có thể thay đổi chữ ký hàm để lấy một mảng các loại đó thay vì sử dụng '...'.

+0

Một mảng của một loại cần lặp lại, trong khi sử dụng hàm variadic cung cấp cơ chế nội tuyến biên dịch thời gian. Bạn có thể nói rằng vòng lặp trên một mảng không phải là thời gian conuming, nhưng xem xét nó trong một vòng lặp lớn khác. – melmi

Các vấn đề liên quan