2015-10-29 29 views
5

Tôi đang cố gắng để viết một hàm trả về một tập hợp con của một gói đối số variadic dưới hình thức một std::tuple. Hàm này lý tưởng không có chi phí thời gian chạy (không cần bản sao không cần thiết) và nó sẽ cho phép người dùng truy cập vào tài liệu tham khảo lvalue và sửa đổi chúng.Xóa rvalueness, giữ tài liệu tham khảo lvalue (tiêu chuẩn loại đặc điểm có sẵn?)

Các loại giá trị, tham chiếu lvalue và tham chiếu const lvalue phải được duy trì. Các tham chiếu thời gian (rvalue), phải được "chuyển đổi" thành các loại giá trị để tránh tạo tham chiếu không hợp lệ (tham chiếu đến thời gian).

Ví dụ về kết quả mong muốn:

int lr = 5; 
const int& clr = lr; 

auto t = make_subpack_tuple(lr, clr, 5); 

static_assert(is_same 
< 
    decltype(t), 
    std::tuple<int&, const int&, int> 
>{}, ""); 

// Ok, modifies lr: 
std::get<0>(t) = 10; 

// Compile-time error, intended: 
// std::get<1>(t) = 20; 

// Ok, 5 was moved into the tuple: 
std::get<2>(t) = 30; 

Ví dụ không đầy đủ thực hiện:

template<typename... Ts> 
auto make_subpack_tuple(Ts&&... xs) 
{ 
    return std::tuple 
    < 
     some_type_trait<decltype(xs)>... 
    > 
    (
     std::forward<decltype(xs)>(xs)... 
    ); 
} 

Liệu những gì tôi đang cố gắng để làm có ý nghĩa?

Có loại đặc điểm tiêu chuẩn nào có thể được sử dụng thay cho some_type_trait không? Hoặc tôi nên thực hiện giải pháp của riêng mình?

+0

Tôi chỉ tò mò thôi. Tại sao bạn quan tâm đến việc này? Bạn đang giải quyết vấn đề gì? –

+0

Tôi đang triển khai một cái gì đó tương tự như 'static_for' thực hiện một đối tượng có thể gọi trên các giá trị không đồng nhất với một người dùng xác định, và cũng cho phép người dùng truy xuất số lặp hiện tại tại thời gian biên dịch và ngắt/tiếp tục * (thoát sớm) * tại thời gian biên dịch bằng cách sử dụng 'static_if'. Một phần của việc thực hiện yêu cầu truyền các đối số 'N' đầu tiên của gói đối số variadic đến một hàm bên trong khác, và tôi đã cố gắng khái quát hóa điều đó bằng cách định nghĩa một số hàm thao tác gói đối số variadic. Khác với 'nth ', tôi yêu cầu 'subpack ' để khái quát hoàn toàn hành vi đó –

+0

Bằng tính xác thực do người dùng chỉ định, tôi có nghĩa là 'static_for' lặp qua các giá trị không đồng nhất trong các nhóm' N' (trong đó 'N' là tham số mẫu được chỉ định bởi người dùng). Đối tượng callable đại diện cho phần thân của 'static_for' cần có một toán tử'() 'với cùng một số nguyên. Ngoài ra, tôi đang làm tất cả điều này cho một thư viện mục đích chung C++ 14 mã nguồn mở ([vrm_core] (https://github.com/SuperV1234/vrm_core)), được viết cho mục đích vui vẻ và học tập. Hy vọng trả lời câu hỏi của bạn :) –

Trả lời

7

Các giải pháp cho bạn sẽ là

template<typename... Ts> 
auto make_subpack_tuple(Ts&&... xs) 
{ 
    return std::tuple<Ts...>(std::forward<Ts>(xs)...); 
} 

Theo template argument deduction rules, tham số gói Ts... sẽ chỉ chứa các loại cv-trình độ và lvalues. Thông tin trong this question cũng có thể hữu ích.

1

Tôi chỉ muốn kêu gọi trong đó tôi gặp phải vấn đề không thực sự giống như vậy ("Tôi nghĩ rằng tôi cần phân tích các tham chiếu rvalue và giữ nguyên tham chiếu lvalue") trong khi triển khai phiên bản hiệu quả Nick Athanasios's foldable Op<operation>. Tôi đã có đống lộn xộn này:

template<class Pack, class Op> 
struct Foldable 
{ 
    mystery_trait_t<Pack> value; 
    const Op& op; 

    template<class RhsPack> 
    auto operator*(const Foldable<RhsPack, Op>& rhs) const { 
     return op(static_cast<std::decay_t<Pack>>(
      (op.f)(std::move(value), std::move(rhs.value)) 
     )); 
    } 

    operator mystery_trait_t<Pack>() && { 
     return std::move(value); 
    } 
}; 

template<class Pack> 
auto NamedOperator::operator()(Pack&& value) const { 
    return Foldable<Pack, NamedOperator>(std::forward<Pack>(value), *this); 
} 

và (sau khi đánh đố cho một chút, và sau đó bắt đầu đặt một câu hỏi SO, và việc tìm kiếm này hiện câu hỏi/câu trả lời, và thêm một static_assert để thực hiện của tôi mystery_trait_t để xác minh rằng nó không bao giờ được thực sự gọi với một loại tài liệu tham khảo rvalue!) nó bật ra rằng tất cả những gì thực sự cần thiết là

template<class Pack, class Op> 
struct Foldable 
{ 
    Pack value; 
    const Op& op; 

    template<class RhsPack> 
    auto operator*(const Foldable<RhsPack, Op>& rhs) const { 
     return op(
      (op.f)(std::move(value), std::move(rhs.value)) 
     ); 
    } 

    operator Pack() && { 
     return std::move(value); 
    } 
}; 

(See my whole code on Wandbox.)

"câu trả lời" này của tôi không đóng góp bất kỳ thông tin mới, nhưng tôi nghĩ nó sẽ hữu ích khi chia sẻ, bởi vì nó chỉ cho thấy rằng ngay cả khi bạn nghĩ mình đang cách sâu trong lập trình meta mẫu và là chắc chắn bạn cần hành vi "phân hủy có điều kiện" này ... bạn thực sự không cần nó !

Có thể có một quy tắc chung về hệ quả là viết any_template<T&&> luôn là một mùi mã. Trong câu hỏi ban đầu của Vittorio, ông đã thực hiện điều đó hai lần, mặc dù cả hai lần nó bị ẩn theo cú pháp decltype:

some_type_trait<decltype(xs)>... // should have been `Ts...` 
std::forward<decltype(xs)>(xs)... // could equally well be `std::forward<Ts>(xs)...` 
Các vấn đề liên quan