8

Giả sử tôi có một mảng constexpr thời gian biên dịch và mẫu lớp variadic với một tập hợp các tham số không loại cùng loại với các phần tử của mảng.Mở rộng một mảng constexpr thành một tập hợp các tham số mẫu không kiểu

Mục tiêu của tôi là để nhanh chóng các lớp mẫu với các giá trị từ mảng:

struct Container 
{ 
    int containee[3]; 
}; 

constexpr Container makeContainer(); 

template <int... Elements> class Foo; 

Foo<makeContainer().containee[0], 
    makeContainer().containee[1], 
    makeContainer().containee[2]> foo; 

Đoạn mã trên hoạt động tốt. Tuy nhiên, tôi hoàn toàn không hài lòng về việc phải lập chỉ mục mảng theo cách thủ công bất cứ khi nào tôi cần tạo mẫu Foo. Tôi muốn trình biên dịch tự động thực hiện việc đó cho tôi:

Foo<Magic(makeContainer().containee)> foo; 

Tôi đã thực hiện một số RTFM ở cppreference, nhưng điều đó không có tác dụng. Tôi biết về std::forward<>(), nhưng không thể áp dụng cho danh sách đối số mẫu.

Trả lời

7
  1. Thay đổi makeContainer đến một struct với một constexpr operator() hoặc một constexpr lambda (C++ 17). Một con trỏ hàm sẽ không hoạt động ở đây.

    struct makeContainer 
    { 
        constexpr auto operator()() const 
        { 
         return Container{/* ... */}; 
        } 
    }; 
    
  2. Sử dụng std::make_index_sequencestd::index_sequence để tạo ra một chuỗi thời gian biên dịch của chỉ số:

    template <typename C> 
    constexpr auto fooFromContainer(const C& container) 
    { 
        return fooFromContainerImpl(container, std::make_index_sequence<3>{}); 
    } 
    
  3. Tạo một trường hợp constexpr container mới qua C, sau đó mở rộng chuỗi để chỉ mục các yếu tố trong một biểu thức liên tục:

    template <typename C, std::size_t... Is> 
    constexpr auto fooFromContainerImpl(const C& container, std::index_sequence<Is...>) 
    { 
        constexpr auto c = container(); 
        return Foo<c.containee[Is]...>{}; 
    } 
    

complete example on wandbox.org


Chỉ cần cho vui, đây là một việc thực hiện C++ 20:

struct container { int _data[3]; }; 

template <int... Is> 
struct foo 
{ 
    constexpr auto t() const { return std::tuple{Is...}; } 
}; 

template <typename C> 
constexpr auto foo_from_container(const C& c) 
{ 
    return []<std::size_t... Is>(const auto& c, std::index_sequence<Is...>) 
    { 
     return foo<c()._data[Is]...>{}; 
    }(c, std::make_index_sequence<3>{}); 
} 

int main() 
{ 
    constexpr auto r = foo_from_container([]{ return container{42, 43, 44}; }); 
    static_assert(r.t() == std::tuple{42, 43, 44}); 
} 

live example on wandbox.org

+1

Đây là tuyệt vời. Tôi không hiểu ý nghĩa của việc nhúng các giá trị trong các loại cho đến khi điều này. –

+2

Người ta có thể sử dụng 'std :: make_index_sequence ' thay vì 'std :: make_index_sequence <3>'. – Constructor

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