2012-05-10 29 views
5
template <int I> struct int_ {}; 

template < typename ... Pack > 
struct thingy 
{ 
    void call() 
    { 
     f(???); 
    } 
}; 

Khi khởi tạo nó nên kết thúc là:interweave một VT giải nén với một meta-chuỗi

struct thingy<int,char,double> 
{ 
    void call() 
    { 
     f(int, int_<1>(), char, int_<2>(), double, int_<3>()); 
    } 
} 

gì bạn nghĩ, nó có thể được thực hiện? Làm sao?

Điều duy nhất tôi có thể nghĩ đến là phải có quá tải cho thingy với N thông số khác nhau như sau:

template < typename T0 > struct thingy<T0> { ... }; 
template < typename T0, typename T1 > struct thingy<T0,T1> { ... }; 

etc... 

Với một thực hiện cuộc gọi trong mỗi.

Trả lời

4

Nó có thể được thực hiện

Vâng, tất nhiên.

Làm cách nào?

Trong một vài bước.

  • Bạn cần để có thể tạo ra một loạt các số nguyên
  • Bạn cần để có thể xen vào giưa hai chuỗi

Chúng ta hãy bắt đầu với hàng loạt các số nguyên.

template <size_t...> 
struct IntegralPack {}; 

template <size_t A, size_t... N> 
IntegralPack<N..., A> push_back(IntegralPack<N...>); 

template <size_t A, size_t... N> 
IntegralPack<A, N...> push_front(IntegralPack<N...>); 

template <size_t L, size_t H> 
struct IntegralRangeImpl { 
    typedef typename IntegralRangeImpl<L+1, H>::type Base; 
    typedef decltype(push_front<L>((Base()))) type; 
}; 

template <size_t X> 
struct IntegralRangeImpl<X, X> { 
    typedef IntegralPack<> type; 
}; 

template <size_t L, size_t H> 
struct IntegralRange { 
    static_assert(L <= H, "Incorrect range"); 
    typedef typename IntegralRangeImpl<L, H>::type type; 
}; 

Bước chuyển đổi rất dễ dàng đủ (may mắn):

template <typename...> 
struct TypePack {}; 

template <size_t... N> 
TypePack<int_<N>...> to_int(IntegralPack<N...>); 

Vì vậy, những khó khăn tiếp theo là hợp nhất.

template <typename... As, typename... Bs> 
TypePack<As..., Bs...> cat(TypePack<As...>, TypePack<Bs...>); 

template <typename, typename> struct Interleaver; 

template <> 
struct Interleaver<TypePack<>, TypePack<>> { 
    typedef TypePack<> type; 
}; 

template <typename A0, typename B0, typename... As, typename... Bs> 
struct Interleaver<TypePack<A0, As...>, TypePack<B0, Bs...>> { 
    typedef typename Interleaver<TypePack<As...>, TypePack<Bs...>>::type Base; 
    typedef decltype(cat(TypePack<A0, B0>{}, Base{})) type; 
}; 

Đưa nó hoàn toàn:

template <typename... Pack> 
struct thingy { 
    typedef typename IntegralRange<1, sizeof...(Pack) + 1>::type Indexes; 
    typedef decltype(to_int(Indexes{})) Ints; 
    typedef typename Interleaver<TypePack<Pack...>, Ints>::type Types; 

    void call() { this->callImpl(Types{}); } 

    template <typename... Ts> 
    void callImpl(TypePack<Ts...>) { 
     f(Ts{}...); 
    } 
}; 

Tadaam!

+0

Câu trả lời hay - điều đó sẽ khiến tôi trở nên hoàn toàn tự tin hơn với những thứ như thế! +1 –

+0

Ngọt ngào. Tôi sẽ phải kiểm tra xem nó ra. Tôi sẽ đăng câu trả lời của riêng tôi mà không làm nó ... nhận được cuộc gọi được thực hiện mà không trả lời câu hỏi đó là. Thật không may, khi tôi đang làm việc trên nó tôi chạy vào rắc rối khác với giao diện của loại cơ bản của tôi, freaked ra một lúc, đã làm một shot, và đi ngủ. –

+0

@CrazyEddie: Tôi rất vui nếu bạn có thể ping tôi (viết bình luận ở đây) khi bạn trả lời :) –

0

Vì vậy, cách tôi đã đi về nó là một chút cụ thể hơn cho những gì tôi đã thực sự làm. Hóa ra một số thông tin tôi nghĩ là bên cạnh điểm đã giúp tôi. Tôi nghĩ rằng mặc dù một kỹ thuật tương tự có thể được sử dụng cho mọi trường hợp.

Đối với một điều ... trong trường hợp của tôi "thingy <>" thực sự có giá trị trong đó và được chuyển đến hàm invoker. Điều này thực sự giúp ích rất nhiều.

Ngoài ra, vì đối tượng là để chuyển đổi nội dung trong thingy để phục vụ như gây ra cho một thingy lạ, và ints được thông qua trong chỉ mục là thingy đầu tiên ... ints kết thúc tất cả là 1 khi tôi làm sự đệ quy của tôi. Vì vậy, trong khi những gì tôi là sau khi một cái gì đó tương tự (đơn giản để loại bỏ các tuple giây):

f(get(my_thingy, idx<1>), get(my_thingy, idx<2>), ...) 

Nó chỉ ra các đệ quy được thoát khỏi idx < 2> ...idx:

template < typename Fun, typename H, typename ... T, typename ... Args > 
auto call(Fun f, thingy<H,T...> const& t, Args&& ... args) 
    -> decltype(call(f,static_cast<thingy<T...>const&>(t), get(t,idx<1>), std::forward<Args>(args)...) 
{ 
    return call(f, static_cast<thingy<T...>const&>(t), get(t, idx<1>), args...); 
} 

template < typename Fun, typename ... Args > 
auto call(Fun f, thingy<> const&, Args&& ... args) 
    -> decltype(f(std::forward<Args>(args)...)) 
{ 
    return f(std::forward<Args>(args)...); 
} 

tôi đã không thể hoàn toàn kiểm tra điều vì get chức năng không thành công trên tôi vì một lý do khi sử dụng const & ... kinda pissing tôi ra. Tôi khá tự tin rằng điều này thực hiện các trick mặc dù.

Nếu tham số idx không phải luôn luôn 1 Tôi nghĩ rằng có thể được chuyển tiếp theo cách tương tự.

+0

'static_cast const &> (t)' điều này có nghĩa là bạn có một hệ thống phân cấp thừa kế ở đây, không khớp với định nghĩa 'thingy' được cung cấp trong câu hỏi: tâm chỉnh sửa định nghĩa mới vào câu trả lời này? –

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