2012-12-17 21 views
8

Có thể ngăn chặn sự phân rã mảng-con trỏ trong đối số được mở rộng từ gói tham số không?ngăn chặn sự phân rã mảng trong việc mở rộng gói tham số

Ví dụ:

#include <iostream> 

void foo() { 
    std::cout << "empty\n"; 
} 

template <typename T, typename... Rest> 
void foo(T &&t, Rest... rest) { 
    std::cout << "T, ...\n"; 
    foo(rest...); 
} 

template <typename... Rest> 
void foo(char *p, Rest... rest) { 
    std::cout << "char*, ...\n"; 
    foo(rest...); 
} 

template <int N, typename... Rest> 
void foo(char (&first)[N], Rest... rest) { 
    std::cout << "char[], ...\n"; 
    foo(rest...); 
} 

int main() { 
    char a[2], b[2], c[2]; 
    foo(a, b, c); 
} 

... kết quả đầu ra:

char[], ... 
char*, ... 
char*, ... 
empty 

Như bạn có thể thấy, cuộc gọi đầu tiên đi vào tình trạng quá tải mảng dựa trên, nhưng các cuộc gọi tiếp theo đi đến pointer- dựa trên quá tải. Có cách nào để nhận tất cả các cuộc gọi đến quá tải dựa trên mảng không?

liên quan: Problems specializing variable template function

+2

'std :: forward (rest) ...'? – Yakk

Trả lời

7

Bạn muốn vượt qua các gói thông số bằng cách tham khảo rvalue:

void foo(char (&first)[N], Rest&&... rest) 
           ^^ 

Vì vậy, các mã trông giống như tổng thể này:

#include <iostream> 

void foo() { 
    std::cout << "empty\n"; 
} 

template <typename T, typename... Rest> 
void foo(T &&t, Rest... rest) { 
    std::cout << "T, ...\n"; 
    foo(rest...); 
} 

template <typename... Rest> 
void foo(char *p, Rest... rest) { 
    std::cout << "char*, ...\n"; 
    foo(rest...); 
} 

template <int N, typename... Rest> 
void foo(char (&first)[N], Rest&&... rest) { 
    std::cout << "char[], ...\n"; 
    foo(rest...); 
} 

int main() { 
    char a[2], b[2], c[2]; 
    foo(a, b, c); 
} 

Cho kết quả:

char[], ... 
char[], ... 
char[], ... 
empty 

Tôi đã không thay đổi các tình trạng quá tải khác để thực hiện tương tự, nhưng bạn thường muốn chúng sử dụng tham chiếu rvalue (nếu chúng thực sự đang được sử dụng).

Chỉnh sửa: Tại sao bạn muốn làm điều này/lý do tại sao nó hoạt động: tham chiếu rvalue có thể liên kết với giá trị rvalue hoặc giá trị. Điểm quan trọng mà chúng tôi quan tâm ở đây là khi nó liên kết với một giá trị, nó vẫn là một giá trị. Trong trường hợp của một mảng, nó giữ lại danh tính của nó như là một mảng, vì vậy những gì nhận được là một mảng.

Khi/nếu chúng ta chuyển một mảng theo giá trị, nó sẽ trải qua "phân rã" bình thường thành con trỏ, giống như với hàm bình thường.

Đối với trường hợp cụ thể này, chúng tôi cũng có thể sử dụng tham chiếu giá trị thông thường - nhưng nếu chúng tôi thực hiện, điều đó sẽ không hoạt động với bất kỳ loại nào không phải là giá trị. Ví dụ: nếu chúng tôi cố gắng gọi foo(1,2,3);, chúng tôi sẽ gặp lỗi vì tham chiếu giá trị không thể liên kết với 1, 2 hoặc 3. Để đối phó với điều đó, chúng tôi có thể chuyển một tham chiếu giá trị const lvalue, nhưng sau đó chúng tôi sẽ không ràng buộc tham chiếu trực tiếp vào giá trị - chúng tôi sẽ tạo tạm thời chứa một bản sao của rvalue đã được chuyển và sau đó ràng buộc thay vào đó, tham chiếu lvalue tới bản sao tạm thời đó. Đối với trường hợp cụ thể của một int, đó có thể sẽ không phải là một vấn đề lớn, nhưng với một cái gì đó là tốn kém hơn để sao chép (hoặc nếu chúng ta muốn truy cập vào bản gốc, không phải là một bản sao) có thể là một vấn đề.

+1

"nhưng bạn thường muốn họ sử dụng tham chiếu rvalue" Tại sao tôi muốn làm điều đó? Tại sao điều này làm việc và OP không? –

+0

@OlafDietsche: Đã chỉnh sửa. –

+1

Cảm ơn rất nhiều vì lời giải thích tuyệt vời này. –

5

@ Câu trả lời của JerryCoffin đã đạt được vị trí rồi, nhưng tôi muốn thêm một nhận xét nhỏ. Bạn có thể tách mã xử lý danh sách khỏi mục như sau:

void foo_list() { 
    std::cout << "empty\n"; 
} 

template <typename T, typename... Rest> 
void foo_list(T &&t, Rest&&... rest) { 
    foo(t); 
    foo_list(rest...); 
} 

template <int N> 
void foo(char (&t)[N]){ 
    // ... 
} 

void foo(char *){ 
    // ... 
} 

// etc... 

(Có thể đã có thành ngữ cho điều đó?).

+0

Đó là một điểm tuyệt vời. –

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