Variadic模板和Alexandrescu元组实现

时间:2014-09-13 14:11:10

标签: c++ variadic-templates

我尝试学习一些关于模板元编程的知识 目前我玩变量模板。

在他的演讲中,“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_的访问规则更改为公共工作。

感谢您的帮助

凯文

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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;
}

实际上,我们不需要Tuple来获取类型。