2017-11-29 38 views
5

Tôi đang học C++ biểu thức gấp và chúng thực sự tốt đẹp để mở rộng một gói thông số. Nhưng nếu tôi phải mở rộng một vài trong số họ trong một cuộc gọi thì sao?Sử dụng hai biểu thức gấp trong một dòng

tôi đã chuẩn bị một ví dụ để làm rõ những gì tôi có nghĩa là:

#include <cstddef> 
#include <iostream> 
#include <utility> 

template< 
    template<size_t ix_, size_t iy_> typename Functor, 
    typename FunctorContext, 
    size_t... ix, 
    size_t... iy> 
void RepeatImpl(
    FunctorContext* context, 
    std::index_sequence<ix...>, 
    std::index_sequence<iy...>) 
{ 
    (Functor<ix, iy>::Execute(context), ...); 
} 

template< 
    template<size_t ix_, size_t iy_> typename Functor, 
    size_t width, size_t height, 
    typename FunctorContext> 
void Repeat(FunctorContext* context) 
{ 
    RepeatImpl<Functor>(
     context, 
     std::make_index_sequence<width>(), 
     std::make_index_sequence<height>()); 
} 

template<size_t ix, size_t iy> 
struct Init2dArrayFunctor 
{ 
    template<typename T> 
    static void Execute(T* array) 
    { 
     array[iy][ix] = 10; 
    } 
}; 

int main(int, const char**) 
{ 
    constexpr size_t w = 10; 
    constexpr size_t h = 10; 
    int array[w][h] { 0 }; 
    Repeat<Init2dArrayFunctor, w, h>(array); 

    for(size_t iy = 0; iy < h; ++iy) 
    { 
     for(size_t ix = 0; ix < w; ++ix) 
     { 
      std::cout << array[iy][ix] << ' '; 
     } 

     std::cout << std::endl; 
    } 

    return 0; 
} 

Câu hỏi của tôi là về dòng này:

(Functor<ix, iy>::Execute(context), ...); 

Trong ví dụ cụ này nó sẽ mở rộng ra các cuộc gọi:

Functor<0, 0>::Execute(context) 
Functor<1, 1>::Execute(context) 
Functor<2, 2>::Execute(context) 
... 

Nhưng tôi cần nó để gọi tất cả các kết hợp của ixiy gói:

Functor<0, 0>::Execute(context) 
Functor<0, 1>::Execute(context) 
Functor<0, 2>::Execute(context) 
... 
Functor<1, 0>::Execute(context) 
Functor<1, 1>::Execute(context) 
Functor<1, 2>::Execute(context) 
... 

Tôi biết rằng tôi có thể làm thêm một lớp để đi bộ qua hàng và cột (hai biểu thức lần trong các phương pháp riêng biệt sau đó):

#include <cstddef> 
#include <iostream> 
#include <utility> 


template< 
    template<size_t ix_, size_t iy_> typename Functor, 
    size_t iRow, 
    typename FunctorContext, 
    size_t... iColumn> 
void RepeatImpl_Row(
    FunctorContext* context, 
    std::index_sequence<iColumn...>) 
{ 
    (Functor<iColumn, iRow>::Execute(context), ...); 
} 

template< 
    template<size_t ix_, size_t iy_> typename Functor, 
    size_t columns, 
    typename FunctorContext, 
    size_t... iRow> 
void RepeatImpl(
    FunctorContext* context, 
    std::index_sequence<iRow...>) 
{ 
    (RepeatImpl_Row<Functor, iRow>(context, std::make_index_sequence<columns>()), ...); 
} 

template< 
    template<size_t ix_, size_t iy_> typename Functor, 
    size_t width, size_t height, 
    typename FunctorContext> 
void Repeat(FunctorContext* context) 
{ 
    RepeatImpl<Functor, width>(
     context, 
     std::make_index_sequence<height>()); 
} 

template<size_t ix, size_t iy> 
struct Init2dArrayFunctor 
{ 
    template<typename T> 
    static void Execute(T* array) 
    { 
     array[iy][ix] = 10; 
    } 
}; 

int main(int, const char**) 
{ 
    constexpr size_t w = 10; 
    constexpr size_t h = 10; 
    int array[w][h] { 0 }; 
    Repeat<Init2dArrayFunctor, w, h>(array); 

    for(size_t iy = 0; iy < h; ++iy) 
    { 
     for(size_t ix = 0; ix < w; ++ix) 
     { 
      std::cout << array[iy][ix] << ' '; 
     } 

     std::cout << std::endl; 
    } 

    return 0; 
} 

Nhưng cách này làm cho mã khó khăn hơn nhiều để đọc. Có lẽ có thể thực hiện thủ thuật này với hai biểu thức trong một dòng?

Trả lời

4

bạn chỉ có thể viết một cái gì đó như:

template< 
    size_t height, 
    template<size_t ix_, size_t iy_> typename Functor, 
    typename FunctorContext, 
    size_t... ixy> 
void RepeatImpl(
    FunctorContext* context, 
    std::index_sequence<ixy...>) 
{ 
    (Functor< ixy/height, ixy % height >::Execute(context), ...); 
} 

template< 
    template<size_t ix_, size_t iy_> typename Functor, 
    size_t width, size_t height, 
    typename FunctorContext> 
void Repeat(FunctorContext* context) 
{ 
    RepeatImpl<height,Functor>(
     context, 
     std::make_index_sequence<width*height>()); 
} 

nó sẽ làm việc khi chúng tôi có các loại variadic, không chỉ số?

chỉ cần bọc danh sách loại vào một kiểu có thể lập chỉ mục trong trường hợp đó.

Nhưng có cách nào để xử lý một vài variadics qua nếp gấp không?

hiện tại, không, tôi không nghĩ là có thể; gói luôn được mở rộng tuyến tính và nếu có nhiều hơn một gói, chúng được mở rộng đồng thời và phải có cùng độ dài, như bạn đã quan sát. Chúng tôi không có hỗ trợ ngôn ngữ 'trực tiếp' để mở rộng gói 'sản phẩm điện'. Nếu bạn muốn một sản phẩm Descartes của một cặp tham số mẫu, bạn sẽ luôn luôn kết thúc với một cái gì đó như trên ...

+0

Giải pháp này sẽ chỉ làm việc cho ví dụ tổng hợp này. Ví dụ, nó sẽ không hoạt động khi chúng ta có các kiểu variadic, không phải các chỉ mục. Tôi đã chuẩn bị ví dụ với các chỉ số vì tôi nghĩ rằng đây là cách đơn giản nhất để giải thích câu hỏi của tôi. –

+0

@ КонстантинЛазукин nó sẽ hoạt động, chỉ cần bọc danh sách loại trong một loại chỉ mục-tuple ... –

+0

tốt, nó là lựa chọn tốt đẹp. Nhưng có cách nào để xử lý một vài variadics qua nếp gấp? Tôi xin lỗi vì những câu hỏi khó chịu này nhưng quan điểm của tôi ở đây là tìm hiểu những gì tôi có thể thực hiện bằng tính năng C++ mới này. –

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