2013-07-22 28 views
6

Tôi hiện đang cố gắng thu hút đầu của mình xung quanh một số điều tôi có thể làm với hỗ trợ mẫu variadic. Giả sử tôi có một chức năng như thế này -C++ Mẫu Chức năng biến thể của loại đã biết

template <typename ... Args> 
void foo(Args ... a) 
{ 
    int len = sizeof...(tail); 
    int vals[] = {a...}; 
    /* Rest of function */ 
} 

/* Elsewhere */ 
foo(1, 2, 3, 4); 

Mã này hoạt động vì tôi cho rằng đối số sẽ là số nguyên, nhưng rõ ràng sẽ thất bại nếu tôi cung cấp cái gì khác. Nếu tôi biết rằng các gói thông số sẽ chứa một loại hình cụ thể trước, có một số cách mà tôi có thể làm mà không có khuôn mẫu và có một cái gì đó giống như -

void foo(int ... a) 

Tôi đã cố gắng làm điều này, nhưng trình biên dịch đưa ra một lỗi về foo là trường trống. Tôi biết rằng tôi cũng có thể truy cập các tham số trong gói thông qua đệ quy, nhưng tôi không chắc chắn điều này sẽ khắc phục được sự cố mà tôi có - cụ thể là tôi muốn có thể lấy một số biến đối số cùng loại.

+1

Bạn có thể sử dụng 'enable_if' để đảm bảo tất cả các loại * là * ints. –

+2

Mã hoạt động nếu bạn đi sâu vào một nhóm int. Nó không hoạt động nếu bạn cho nó cái gì khác. Có vẻ như nhiệm vụ đã hoàn thành. Vấn đề ở đâu? –

+0

Tôi đoán vấn đề là liệu có thể đảm bảo rằng chúng là ints tại thời gian biên dịch hay không. – znby

Trả lời

3

Nếu bạn biết các loại trước đây, bạn có thể sử dụng chức năng quá tải với std:initializer_list:

#include <initializer_list> 
#include <iostream> 

void foo(std::initializer_list<int> l) 
{ 
    for (auto el : l) 
     // do something 
} 

void foo(std::initializer_list<float> l) 
{ 
} 

void foo(std::initializer_list<std::string> l) 
{ 
} 

int main() 
{ 
    foo({1, 2, 3, 4 }); 
    foo({1.1f, 2.1f, 3.1f, 4.1f }); 
    foo({ "foo", "bar", "foo", "foo" }); 
    return 0; 
} 

Nếu bạn sử dụng Visual Studio 2012, bạn có thể cần Visual C++ Compiler November 2012 CTP.

EDIT: Nếu bạn vẫn muốn sử dụng mẫu variadic, bạn có thể làm:

template <int ... Args> 
void foo() 
{ 
    int len = sizeof...(Args); 
    int vals[] = {Args...}; 
    // ... 
} 

// And 

foo<1, 2, 3, 4>(); 

Nhưng bạn phải nhớ rằng nó không phải đang làm việc với floatstd::string ví dụ: bạn sẽ kết thúc với 'float': illegal type for non-type template parameter . float không hợp pháp như là non-type template parameter, điều này là để làm với độ chính xác, số dấu chấm động không thể được biểu diễn chính xác và khả năng bạn tham chiếu cùng loại có thể phụ thuộc vào cách số được biểu diễn.

+0

Nếu bạn cần biết số đối số tại thời gian biên dịch, cách giải quyết này là không đủ, bởi vì 'initializer_list' không cung cấp thành viên' constexpr size() '. AFAIK, không có cách nào xung quanh các mẫu variadic với kiểm tra 'is_same <>/is_convertible <>'. – user2523017

+0

@ user2523017 Bạn nói đúng, với giải pháp này, chúng tôi không thể có số đối số tại thời gian biên dịch. –

1

Tôi hiện đang cố gắng làm quen với một số điều tôi có thể làm với hỗ trợ mẫu variadic.

Giả sử rằng bạn muốn thử nghiệm với các mẫu variadic, không tìm thấy giải pháp nào cho vấn đề của bạn, sau đó tôi khuyên bạn nên nhìn vào mã bên dưới:

#include <iostream> 

template<int ...Values> 
void foo2() 
{ 
    int len = sizeof...(Values); 
    int vals[] = {Values...}; 

    for (int i = 0; i < len; ++i) 
    { 
     std::cout << vals[i] << std::endl; 
    } 
} 

int main() 
{ 
    foo2<1, 2, 3, 4>(); 

    return 0; 
} 

Sự khác biệt giữa foo2 và bạn foo là bạn chuyển các tham số tới foo khi đang chạy và đến foo2 lúc biên dịch, vì vậy đối với mỗi bộ tham số bạn sử dụng, trình biên dịch sẽ tạo ra một hàm chức năng riêng biệt foo2.

10

này nên làm việc:

void foo(int); 

template<typename ...Args> 
void foo(int first, Args... more) 
{ 
    foo(first); 
    foo(std::forward(more)...); 
} 
+0

Câu trả lời này phù hợp hơn với những gì OP yêu cầu. Nhược điểm duy nhất của giải pháp này là phần đệ quy. Nhưng ngay bây giờ tôi có thể thấy một giải pháp tốt hơn, thậm chí không bằng cách sử dụng C++ 17 và biểu thức gấp. – mic

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