2011-12-20 28 views
10

Giả sử tôi có hai struct s:Perfect chuyển tiếp thành viên của đối tượng

struct X {}; 
struct Y { X x; } 

tôi có chức năng:

void f(X&); 
void f(X&&); 

Làm thế nào để viết một hàm g() rằng mất Y& hoặc Y&& nhưng hoàn hảo chuyển tiếp X& hoặc X&& đến f(), tương ứng:

template <typename T> 
void g(T&& t) { 
    if (is_lvalue_reference<T>::value) { 
    f(t.x); 
    } else { 
    f(move(t.x)); 
    } 
} 

Mã trên minh họa ý định của tôi nhưng không thể mở rộng được vì số lượng tham số tăng lên. Có cách nào làm cho nó hoạt động để chuyển tiếp hoàn hảo và làm cho nó có khả năng mở rộng?

+0

Tôi nghĩ rằng thay đổi 'is_lvalue_reference :: giá trị' cho 'is_lvalue_reference (t))> :: giá trị' sẽ có ngữ nghĩa mà bạn muốn, nhưng tôi nghĩ ngữ nghĩa mong muốn của bạn là có vấn đề ... – ildjarn

+0

(Xin lỗi vì câu trả lời bị hỏng). Tôi muốn nói lý do không quy mô là vì thiết kế là có vấn đề để bắt đầu. "Di chuyển" một subobject nghĩa là gì? Trong trạng thái nào điều này rời khỏi đối tượng chính? Ngay cả khi có một cách dễ dàng để viết điều này, nó trông giống như mã có cấu trúc kém ... –

Trả lời

15
template <typename T> 
void g(T&& t) { 
    f(std::forward<T>(t).x); 
} 
+1

có vẻ tốt với tôi http://ideone.com/Edf4o –

+0

Giải pháp đẹp hơn nhiều, nhưng tại sao chính xác nó hoạt động? – Pubby

+0

@Pubby vì 'rvalue.foo' là một giá trị. Tôi có thể nghĩ tại sao nó có thể có ý nghĩa (nếu thùng chứa có tuổi thọ ngắn và là giá trị, vật thể chứa quá chia sẻ tài sản đó), nhưng tôi không quen thuộc với các triết lý và không biết lý do, vì vậy tôi không thể nói gì về nó. –

3

Tôi nghĩ rằng đây sẽ làm việc, mặc dù tôi không chắc chắn:

template<class T, class M> 
struct mforward { 
    using type = M&&; 
}; 
template<class T, class M> 
struct mforward<T&, M> { 
    using type = M&; 
}; 

template <typename T> 
void g(T&& t) { 
    f(std::forward<typename mforward<T, decltype(t.x)>::type>(t.x)); 
} 
+2

+1 Tôi đã phải giải quyết gần như vấn đề chính xác này trong libC++. Giải pháp tôi đưa ra trông rất giống với Pubby. Không chỉ tôi muốn "áp dụng" l/r-giá trị của 'T' để' M', tôi cũng muốn áp dụng cv-trình độ của 'T' để' M'. Và tôi đã tìm thấy các ứng dụng cho nó ngoài các thành viên dữ liệu. Đối với những người tò mò, tôi gọi nó là '__apply_cv' và nó là mã nguồn mở tại: http://libcxx.llvm.org/ –

+0

@Howard thấy câu trả lời của tôi cho một sự thay thế. Hay tôi nhớ điều gì đó? –

+0

Ngoài ra @Howard nói về trình độ cv làm cho tôi suy nghĩ về một lỗ hổng của câu trả lời này. 'decltype (t.x)' chỉ cung cấp cho bạn kiểu khai báo 'x'. Nếu 'T' là' const', nhưng 'x' được khai báo là' int a' thì tiến trình của bạn sẽ cố chuyển tiếp các thứ như 'int &'/'int &&'. Bạn sẽ cần phải nói một cái gì đó như 'typename remove_reference :: type' để đưa vào tài khoản constness' t' quá. Điều này cũng đưa vào tài khoản các thành viên 'mutable', nhưng tôi không biết di chuyển có ý nghĩa gì về mặt triết học đối với một thành viên có thể thay đổi được của một đối tượng' const' khác. –

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