2014-09-13 13 views
5

Tôi cố gắng tìm hiểu một chút về lập trình meta mẫu và hiện tại tôi đang phát xung quanh với các mẫu có định dạng variadic.Các mẫu biến thể và triển khai thực hiện torrent Alexandrescu

Trong bài nói chuyện của mình "Mẫu biến thể là Funadic" Alexandrescu giới thiệu triển khai tuple nhỏ, mà tôi cố gắng xây dựng và có thể mở rộng một chút . (Tôi biết nó là một ví dụ đồ chơi, tôi chỉ cố gắng tìm hiểu một chút bit nhiều hơn về c + +). Tuy nhiên, tôi có một vấn đề nhỏ với mã của anh ấy.

Ở đây là:

template <typename... Ts> 
class tuple 
{}; 

template<size_t, typename> struct tuple_element; 

template<typename T, typename... Ts> 
struct tuple_element<0, tuple<T, Ts...>> 
{ 
    typedef T type; 
}; 

template <size_t k, typename T, typename... Ts> 
struct tuple_element<k, tuple<T, Ts...>> 
{ 
    typedef 
     typename tuple_element<k-1,tuple<Ts...>>::type type; 
}; 

template<size_t k, typename... Ts> 
typename std::enable_if<k == 0, 
         typename tuple_element<0,tuple<Ts...>>::type&>::type 
    get(tuple<Ts...>& t) 
{return t.head_;} 

template<size_t k, typename T, typename... Ts> 
typename std::enable_if<k != 0, 
         typename tuple_element<k,tuple<T,Ts...>>::type&>::type 
    get(tuple<T,Ts...>& t) 
{ 
    tuple<Ts...> & super = t; 
    return get<k-1>(super); 
} 

template <typename T, typename... Ts> 
class tuple<T,Ts...> : private tuple<Ts...> 
{ 
private: 
    T head_; 

}; 

int main(int argc, char *argv[]) 
{ 
    tuple<int,std::string> t; 
    get<0>(t) = 10; 
    get<1>(t) = std::string("test"); 
    std::cout<<get<0>(t)<<std::endl; 
} 

Để hoạt động chính xác, các chức năng get phải là bạn của lớp tuple (Nó cũng được đề cập trên slide này, xem 32). Nhưng làm thế nào hiện tuyên bố kết bạn như thế nào? Tôi đã thử các cách tiếp cận khác nhau nhưng không thể làm cho nó hoạt động. Khi tôi thay đổi mã từ kế thừa riêng thành công khai và thay đổi quy tắc truy cập cho head_ thành công khai, nó hoạt động.

Nhờ sự giúp đỡ của bạn

Kevin

+1

'std :: end' trên dòng thứ hai đến dòng cuối cùng phải là' std :: endl'. – 0x499602D2

+0

Cảm ơn bạn. Đã sửa nó! – IcePic

Trả lời

4

này làm việc cho tôi:

template <typename T, typename... Ts> 
class tuple<T,Ts...> : private tuple<Ts...> 
{ 
private: 
    T head_; 

    template<size_t k, typename T1, typename... T1s> 
    friend typename std::enable_if<k != 0, 
         typename tuple_element<k,tuple<T1,T1s...>>::type&>::type 
    get(tuple<T1,T1s...>& t); 

    template<size_t k, typename... T1s> 
    friend typename std::enable_if<k == 0, 
         typename tuple_element<0,tuple<T1s...>>::type&>::type 
    get(tuple<T1s...>& t); 

}; 

Demo.

+0

Cảm ơn bạn. Tôi đã thử điều này trước đây nhưng quên thay đổi tên mẫu. – IcePic

0

Một thực hiện từ quan điểm khác xem:

#include <iostream> 
#include <type_traits> 

template <class... Args> 
class Tuple; 

template <> 
class Tuple<> {}; 

template <class T, class... Args> 
class Tuple<T, Args...>: public Tuple<Args...> { 
    using Base = Tuple<Args...>; 
    T Value_; 

public: 
    Tuple(T&& value, Args&&... args) 
     : Value_(std::forward<T>(value)) 
     , Base(std::forward<Args>(args)...) 
    { 
    } 
    T& Value() { 
     return Value_; 
    } 
}; 

template <size_t k, class T, class... Args> 
struct Select { 
    using Type = typename Select<k - 1, Args...>::Type; 
}; 

template <class T, class... Args> 
struct Select<0, T, Args...> { 
    using Type = T; 
}; 

template <size_t k, class... Args> 
using TSelect = typename Select<k, Args...>::Type; 

template <bool P, class T> 
using TEnableIf = typename std::enable_if<P, T>::type; 

template <size_t k, class T, class... Args> 
TEnableIf<(k != 0), TSelect<k, T, Args...>&> get(Tuple<T, Args...>& t) { 
    return get<k - 1, Args...>(t); 
} 

template <size_t k, class T, class... Args> 
TEnableIf<(k == 0), TSelect<k, T, Args...>&> get(Tuple<T, Args...>& t) { 
    return t.Value(); 
} 

int main() { 
    Tuple<int, char> t(1, 'a'); 
    std::cout << get<0>(t) << std::endl; 
    std::cout << get<1>(t) << std::endl; 
    get<1>(t) = 'b'; 
    std::cout << get<1>(t) << std::endl; 
} 

Trên thực tế, chúng ta không cần một tuple để có được một kiểu.

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