首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >c++模板:成员专门化问题

c++模板:成员专门化问题
EN

Stack Overflow用户
提问于 2010-03-27 01:21:40
回答 4查看 368关注 0票数 1

我正在尝试创建一个模板"AutoClass“,它创建一个具有任意成员集的任意类,例如:

代码语言:javascript
复制
AutoClass<int,int,double,double> a;
a.set(1,1);
a.set(0,2);
a.set(3,99.7);
std::cout << "Hello world! " << a.get(0) << " " << a.get(1) << " " << a.get(3) << std::endl;

到目前为止,我已经有了一个具有工作“AutoClass”成员的set:

代码语言:javascript
复制
class nothing {};

template <  typename T1 = nothing, typename T2 = nothing, typename T3 = nothing,
            typename T4 = nothing, typename T5 = nothing, typename T6 = nothing>
class AutoClass;

template <>
class AutoClass<nothing, nothing, nothing,
                nothing, nothing, nothing>
{
    public:
    template <typename U> void set(int n,U v){}
};

template <  typename T1, typename T2, typename T3,
            typename T4, typename T5, typename T6>
class AutoClass: AutoClass<T2,T3,T4,T5,T6>
{
    public:
    T1 V;
    template <typename U> void set(int n,U v)
    {
        if (n <= 0)
            V = v;
        else
            AutoClass<T2,T3,T4,T5,T6>::set(n-1,v);
    }
};

我开始在实现相应的"get“时遇到问题。这种方法不能编译:

代码语言:javascript
复制
template <  typename T1, typename T2, typename T3,
            typename T4, typename T5, typename T6>
class AutoClass: AutoClass<T2,T3,T4,T5,T6>
{
    public:
    T1 V;
    template <typename U> void set(int n,U v)
    {
        if (n <= 0)
            V = v;
        else
            AutoClass<T2,T3,T4,T5,T6>::set(n-1,v);
    }
    template <typename W> W get(int n)
    {
        if (n <= 0)
            return V;
        else
            return AutoClass<T2,T3,T4,T5,T6>::get(n-1);
    }
    template <> T1 get(int n)
    {
        if (n <= 0)
            return V;
        else
            return AutoClass<T2,T3,T4,T5,T6>::get(n-1);
    }
};

此外,我似乎需要为<nothing, nothing, nothing, nothing, nothing, nothing>专门化实现get。有没有办法解决这个问题?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-03-27 02:43:24

首先,我更喜欢Boost.Fusion而不是Boost.Tuple,因为我认为它支持模板元编程和运行时算法的更好的混合。

举个例子,我想向你们展示一个小奇迹:

代码语言:javascript
复制
struct Name {}; extern const Name name;
struct GivenName {}; extern const GivenName givenName;
struct Age {}; extern const Age age;

class Person
{
public:
  template <class T>
  struct value
  {
    typedef typename boost::fusion::result_of::at_key<data_type const,T>::type type;
  };

  template <class T>
  struct has
  {
    typedef typename boost::fusion::result_of::has_key<data_type,T>::type type;
  };

  template <class T>
  typename value<T>::type
  get(T) { return boost::fusion::at_key<T>(mData); }

  template <class T>
  Person& set(T, typename value<T>::type v)
  {
    boost::fusion::at_key<T>(mData) = v; return *this;
  };

private:
  typedef boost::fusion::map <
    std::pair<Name, std::string>,
    std::pair<GivenName, std::string>,
    std::pair<Age, unsigned short>
  > data_type;
  data_type mData;
};

使用它真的很有趣:

代码语言:javascript
复制
Person p;
p.set(name, "Rabbit").set(givenName, "Roger").set(age, 22);

嗯,我自己更喜欢按类索引而不是按索引,因为我既可以传达含义,也可以添加类型检查;)

票数 3
EN

Stack Overflow用户

发布于 2010-03-27 01:26:58

我可以推荐使用Boost库的大量(且经过良好测试且跨平台的)模板-magicky类吗?听起来你要找的是boost::tuple。任何时候你都可以不用写自己的代码-尤其是在使用模板的复杂情况下-你应该使用别人的代码。

票数 3
EN

Stack Overflow用户

发布于 2010-03-27 02:28:58

正如其他人所提到的,通过重用Boost或其他地方的现有实现,您可能能够得到您想要的东西。

如果你想做一些使用这些工具无法完成的事情,或者你很好奇:

  • 尝试将伪可变模板排除在implementation
  • use类型列表之外,以允许递归元函数等。如果需要,
  • 使用伪可变模板作为在编译时尽可能多地转发到
  • 的接口,特别是检查索引等。

一种简单的方法是,为了方便使用MPL,可能如下所示:

代码语言:javascript
复制
template<class Types, size_t N> struct holder 
  // recursively derive from holder types:
  : holder<Types, N-1> 
{
    typename boost::mpl::at_c<Types,N>::type value;
};

// specialization that terminates the recursive derivation:
template<class Types> struct holder<Types,0> {
    typename boost::mpl::at_c<Types,0>::type value;
};

template<class Types>
class AutoClass 
  // recursively derive from holder types:
  : holder<Types, boost::mpl::size<Types>::value-1>    
{
    enum { n = boost::mpl::size<Types>::value };
public:
    template<size_t N, class U> void set(const U& u) {
        // index check at compile time:
        BOOST_STATIC_ASSERT((N < n));
        // cast to responsible holder base:
        static_cast<holder<Types,N>*>(this)->value = u;
    }
    template<size_t N> typename boost::mpl::at_c<Types,N>::type get() const { 
        // index check at compile time:
        BOOST_STATIC_ASSERT((N < n));
        // cast to responsible holder base:
        return static_cast<const holder<Types,N>*>(this)->value;
    } 
};

用法:

代码语言:javascript
复制
typedef boost::mpl::vector<int,std::string> Types;
AutoClass<Types> a;

a.set<0>(42);
assert(a.get<0>() == 42);
a.set<1>("abcde");
assert(a.get<1>() == "abcde");

请记住,为了方便最终用户,仍然可以使用伪可变模板对其进行包装。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2525277

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档