2014-09-13 56 views
5

我嘗試學習一點關於模板元編程和 當前我使用variadic模板。Variadic模板和Alexandrescu元組實現

在他的演講「Variadic模板是Funadic」Alexandrescu介紹了一個小的元組實現,我嘗試構建並可能擴展一點點 一個 小元組實現。 (我知道這是一個玩具的例子,我只是嘗試學習一點點關於C++的更多內容)。但是,我的代碼有一個小問題。

這就是:

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; 
} 

爲了正常工作,get函數必須是 元組類的朋友(也被這個幻燈片中提到,見32)。但是如何 做朋友聲明?我嘗試了不同的方法 ,但無法使其工作。當我將代碼從私有繼承改爲公共繼承 並將head_的訪問規則更改爲公共時,它就可以工作。

感謝您的幫助

凱文

+1

倒數第二行的'std :: end'應該是'std :: endl'。 – 0x499602D2 2014-09-13 14:33:29

+0

謝謝。修復! – IcePic 2014-09-15 14:26:28

回答

4

這個工作對我來說:

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

謝謝。我之前嘗試過,但忘記更改模板名稱。 – IcePic 2014-09-15 14:25:11

0

從其他角度另一種實現:

#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; 
} 

其實,我們並不需要一個元組得到一個類型。