C++模板:成员专业化的问题

C++模板:成员专业化的问题,c++,templates,member,specialization,C++,Templates,Member,Specialization,我正在尝试创建一个模板自动类,该类创建具有任意成员集的任意类,例如: 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<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;
到目前为止,我有一个带有工作集成员的自动类:

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时遇到问题。这种方法不会编译:

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

此外,似乎我需要为专业化实现get。关于如何解决这个问题,有什么想法吗?

我可以推荐使用Boost库中广泛且经过良好测试的跨平台模板magicky类吗?听起来你要找的是。任何时候你都可以不编写自己的代码,尤其是在使用模板的复杂情况下,你应该使用其他人的代码。

我是否可以推荐使用Boost库中广泛且经过良好测试的跨平台模板magicky类集?听起来你要找的是。任何时候都可以不编写自己的代码,特别是在使用模板的复杂情况下,您应该使用其他人的代码。

由于您的基本情况,您需要实现。考虑:

考虑在n为5的完整自动类上调用此函数时会发生什么。它创建了一个有5个成员的自动类,并调用n=4…,然后再次调用,直到达到这一点:

当然,对这个自动类的调用不会发生,但是编译器无论如何都必须编译代码,因为您已经告诉了它

您还需要创建一个自动类::get,因为n可能是1093

我看不出用你当前的界面解决这个问题的方法。如果你把n放在模板参数中,你可以做一个特殊的例子,它不会这样做。在这种情况下,你不能。我想你会遇到很多问题,因为你选择了这个界面,而这个界面将很难解决。例如,当W为“int”但AutoClass::getn-1返回一个double或更糟的值时会发生什么情况,完全不兼容?

由于基本情况,您需要为实现。考虑:

考虑在n为5的完整自动类上调用此函数时会发生什么。它创建了一个有5个成员的自动类,并调用n=4…,然后再次调用,直到达到这一点:

当然,对这个自动类的调用不会发生,但是编译器无论如何都必须编译代码,因为您已经告诉了它

您还需要创建一个自动类::get,因为n可能是1093


我看不出用你当前的界面解决这个问题的方法。如果你把n放在模板参数中,你可以做一个特殊的例子,它不会这样做。在这种情况下,你不能。我想你会遇到很多问题,因为你选择了这个界面,而这个界面将很难解决。例如,当W为“int”但AutoClass::getn-1返回一个double或更糟的值时会发生什么情况,完全不兼容?

正如其他人所提到的,您应该能够通过重用Boost或其他地方的现有实现来达到目的

如果你想做一些用这些工具做不到的事情,或者你很好奇:

尝试将伪变量模板排除在实现之外 使用类型列表来允许递归元函数等。 如果需要,可以使用伪变量模板作为接口 执行 在编译时做尽可能多的工作,尤其是检查索引等。 为方便起见利用MPL的简单方法可能如下所示:

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;
};
用法:

Person p;
p.set(name, "Rabbit").set(givenName, "Roger").set(age, 22);

请记住,为了方便最终用户,这仍然可以用伪变量模板包装。

正如其他人所提到的,您可能应该能够通过重用Boost或其他地方的现有实现来达到您想要的目的

如果你想做一些用这些工具做不到的事情,或者你很好奇:

尝试将伪变量模板排除在实现之外 使用类型列表来允许递归元函数等。 如果需要,可以使用伪变量模板作为接口 执行 在编译时做尽可能多的工作,尤其是检查索引等。 为方便起见利用MPL的简单方法可能如下所示:

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;
};
用法:

Person p;
p.set(name, "Rabbit").set(givenName, "Roger").set(age, 22);
请记住,为了方便最终用户,这仍然可以用伪变量模板包装。

首先,我更喜欢Boost.Tuple,因为它支持更好地混合模板元编程和运行时算法

例如,我想给大家介绍一个小奇迹:

嗯,我自己更喜欢按类而不是按索引编制索引,因为我既能传达含义,又能添加类型检查

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

例如,我想给大家介绍一个小奇迹:

嗯,我自己更喜欢按类索引,而不是按索引索引

,因为我既能传达含义,又能添加类型检查

我知道boost::tuple。但是,我想向这个类模板添加更多不在boost::tuple上的方法。所以我试着用这种方式实现它。但是我同意,通常使用已知的库比重新发明轮子更好。您是否尝试过通过创建新函数简单地向boost::tuple添加额外的功能?你在寻找什么额外的功能?也许你可以将其子类化或添加额外的模板函数来实现其他功能。我正在寻找一种方法,使用这个自动类的成员自动为一个Arbitrary函数提供数据,该函数在编译时检查参数的数量和类型time@ChAoS当前位置如果你所做的不是学习锻炼,一定要用boost。我认为你想要的是可能的,所以请随便问一个关于如何做到这一点的问题。只要快速浏览一下,我就会发现使用Boost.PP生成N个函数,这些函数将元组解压到所需函数的参数中。你会像tuple_调用tuple,someFunction一样使用它。我知道boost::tuple。但是,我想向这个类模板添加更多不在boost::tuple上的方法。所以我试着用这种方式实现它。但是我同意,通常使用已知的库比重新发明轮子更好。您是否尝试过通过创建新函数简单地向boost::tuple添加额外的功能?你在寻找什么额外的功能?也许你可以将其子类化或添加额外的模板函数来实现其他功能。我正在寻找一种方法,使用这个自动类的成员自动为一个Arbitrary函数提供数据,该函数在编译时检查参数的数量和类型time@ChAoS当前位置如果你所做的不是学习锻炼,一定要用boost。我认为你想要的是可能的,所以请随便问一个关于如何做到这一点的问题。只要快速浏览一下,我就会发现使用Boost.PP生成N个函数,这些函数将元组解压到所需函数的参数中。你会像tuple_调用tuple,someFunction一样使用它。是的,我知道这个问题。也许你对把索引n像a.get一样放入模板的评论是个好主意,但我不知道怎么做。你至少需要再写一个元函数:return\u type。然后,您的函数将结束签名:templatetypename return\u type::type get;使用类似的方法,但使用模板专门化作为递归,而不是函数递归。是的,我知道这个问题。也许你对把索引n像a.get一样放入模板的评论是个好主意,但我不知道怎么做。你至少需要再写一个元函数:return\u type。然后,您的函数将结束签名:templatetypename return\u type::type get;使用到目前为止使用的类似方法,但使用模板专门化作为递归而不是函数递归。我喜欢基于标记的索引的想法,+1。使用Boost.Fusion集合保存数据还有另一个好处>,这几乎就像获得了反射一样,因此可以自动打印以进行调试,序列化和反序列化,消息的编码和解码等…我喜欢基于标记的索引的想法,+1。使用Boost.Fusion收集来保存数据还有另一个好处>这几乎就像你获得了反射一样,因此你可以自动打印以进行调试、序列化和反序列化,消息的编码和解码等…谢谢大家,我将尝试使用Boost.Fusion来实现此功能。谢谢大家,我将尝试使用Boost.Fusion来实现此功能。
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;
};
Person p;
p.set(name, "Rabbit").set(givenName, "Roger").set(age, 22);