2011-11-25 27 views
6

Tôi gặp một số khó khăn với việc chuyển tiếp hoàn hảo. Dưới đây là mức độ hiểu biết hiện tại của tôi: keo Mẫu + tham chiếu rvalue + std :: phía trước và một chế độ ma thuật đặc biệt được kích hoạt khi các quy tắc khấu trừ mẫu không có cùng ý nghĩa như thường lệ, nhưng được chế tác để cho phép chuyển tiếp hoàn hảo. Ví dụ:Hoàn hảo chuyển tiếp và std :: tuple (hoặc lớp templated khác)

template <typename T> 
void outer(T&& t) 
{ 
    inner(std::forward<T>(t)); // perfect forwarding activated 
} 

Nhưng điều gì sẽ xảy ra nếu T thực sự là một lớp templated? Ví dụ: làm thế nào tôi có thể hoàn thiện chuyển tiếp tiêu đề :: tuple? Nếu sử dụng T & & làm aboce, tôi sẽ mất tất cả thông tin về các đối tượng chứa trong bộ dữ liệu.
Tuy nhiên đoạn mã sau không thể làm việc:

template <typename... Args> 
void outer(std::tuple<Args...>&& t) 
{ 
    inner(std::forward<std::tuple<Args...>>(t)); 
    use_args_types_for_something_else<Args...>(); // I need to have Args available 
} 

int main() 
{ 
    std::tuple<int, double, float> t(4, 5.0, 4.0f); 
    outer(t); 
} 

cuối chụp gcc nói:

error: cannot bind 'std::tuple<int, double, float> lvalue to 
std::tuple<int, double, float>&& 

Vì vậy, rõ ràng, chúng tôi vẫn đang trong chung, không mẫu trường hợp vế trái không thể ràng buộc để tham khảo rvalue. "Chế độ forwading Perfect" không được kích hoạt

Vì vậy, tôi đã cố gắng để được lén lút và vượt qua tuple của tôi như là một mẫu template:

template < 
    typename... Args 
    template <typename...> class T 
> 
void outer(T<Args...>&& t) 
{ 
    inner(std::forward<T<Args...>>(t)); 
    use_args_type_for_something_else<Args...>(); 
} 

Nhưng tôi vẫn nhận được lỗi tương tự.

+0

Bạn không thể gọi std :: forward mà không chỉ định loại (vì đó là chức năng mẫu và có thể sử dụng khấu trừ)? 'std :: forward (t)' – SoapBox

Trả lời

3

Perfect chuyển tiếp chỉ hoạt động nếu kiểu của tham số là một kiểu mẫu cho các chức năng, vì vậy cách duy nhất để đạt được chuyển tiếp hoàn hảo cũng giống như trong ví dụ đầu tiên của bạn:

template <typename T> 
void outer(T&& t) 
{ 
    inner(std::forward<T>(t)); // perfect forwarding activated 
} 

Các công trình trên vì nó là trường hợp đặc biệt trong đó T được suy ra là SomeType& hoặc SomeType&&.

Điều này, tuy nhiên, không có nghĩa là thông tin loại cho các phần tử tuple bị mất. Nó vẫn còn có thể khôi phục được (mặc dù tôi không nghĩ rằng bạn có thể gõ một gói mẫu variadic). Ví dụ: bạn vẫn có thể gọi số use_args_types_for_something_else như sau:

template <class T> 
struct call_uses_args; 

template <class ...Args> 
struct call_uses_args<std::tuple<Args...>> 
{ 
    void call() const { use_args_types_for_something_else<Args...>(); } 
}; 

template <typename TupleT> 
void outer(TupleT&& t) 
{ 
    inner(std::forward<TupleT>(t)); 
    call_uses_args<typename std::remove_reference<TupleT>::type>().call(); 
} 

Có thể không có giải pháp chung tốt, tuy nhiên, hy vọng tình huống như vậy rất hiếm. (Ví dụ, trong ví dụ cụ thể này, có thể đơn giản chỉ là quá tải outer.)

+0

Cảm ơn câu trả lời tốt đẹp và chính xác của bạn. Vì vậy, liên quan đến chuyển tiếp hoàn hảo trong c + + 11, tôi vẫn cảm thấy một chút đáng lo ngại rằng nó dựa rất nhiều vào combo lạ này "template + rref + std :: forward". Nó tạo ra một điểm nhỏ trong đó quy tắc chung (như "tham chiếu rvalue CHỈ liên kết với rvalue") không áp dụng nữa. Tôi tự hỏi nếu một số cú pháp đặc biệt cho chuyển tiếp hoàn hảo sẽ không được tốt hơn cho c + + 11. Dù sao, đúng là một cách giải quyết trong trường hợp này không phải là lớn của một thỏa thuận vì nó vẫn có thể làm cho hai quá tải cho 'bên ngoài', một với const ref và một với rref để thi đua PF. –

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