【问题标题】:How to inherit from a list of types and then call a member on the list of inherited members?如何从类型列表中继承,然后调用继承成员列表中的成员?
【发布时间】:2011-11-13 05:22:50
【问题描述】:

我有一组具有以下结构的类:

class U
{
public:
    explicit U(int) { ... }
    U() {...}
    Init(int) {...}
};

我需要能够将这些类中的一个或多个组合成一个类 X。伪代码:

template<class TypeSequence>
class X that derives publicly from all the classes in TypeSequence
{
    X(int): all bases are initialized with the integer passed 
    {}
    //if the above constructor is impossible, then the following will do as well:
    X(int)
    {
        Call Init on all bases and pass the given int to them.
    }
};

我想我需要很多 mpl,但我并不擅长。我想做什么可行吗?一个代码示例会很棒。

我的错误:忘了说我不能使用 C++11 功能。我正在寻找 MPL 解决方案。

【问题讨论】:

  • +1 好问题。顺便说一下,你听说过mixin吗?也许,它可以在这里应用,或者它的变体?
  • 我以前用Boost.MPL 做过这个,但我手头没有代码,现在也没有时间写一个完整的答案。如果到那时还没有人回答,我今晚会重新讨论这个问题。作为提示,我记得制作了一个特殊的 mixin,它接受两个 boost::mpl::vector&lt;&gt; 迭代器作为模板参数。
  • U 和 TypeSequence 有什么关系?
  • @Nawaz:我认为 mixin 不适用。我不需要有关 U 类中派生类的信息。我需要类似于 mpl::inherit_linearly 的东西,我只是不知道语法。我也不知道如何初始化基础或在它们上调用 Init
  • 肯定需要C++0x的可变参数模板特性。

标签: c++ templates boost metaprogramming boost-mpl


【解决方案1】:

嗯,Boost.MPL 包含元函数inheritinherit_linearly,您可以将它们与for_each 组合以获得第二个变体(带有初始化函数)。或者只使用 boost::mpl::fold 和自定义元函数:

struct Null_IntConstructor
{
  Null_IntConstructor(int) { }
};

struct InheritFrom_IntConstructor_Folder
{
  template<typename T1, typename T2>
  struct apply
  {
    struct type : T1, T2
    {
      type(int x) : T1(x), T2(x) { }
    };
  };
};

template<typename Bases>
struct InheritFrom_IntConstructor 
  : boost::mpl::fold<Bases, 
                     Null_IntConstructor,
                     InheritFrom_IntConstructor_Folder>::type
{
  InheritFrom_IntConstructor(int x) 
    : boost::mpl::fold<Bases, 
                       Null_IntConstructor,
                       InheritFrom_IntConstructor_Folder>::type(x) 
  { }
};

使用示例:

#include <iostream>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/vector.hpp>

struct A
{
  A(int x) { std::cout << "A::A " << x << std::endl; }
};

struct B
{
  B(int x) { std::cout << "B::B " << x << std::endl; }
};

struct C
{
  C(int x) { std::cout << "C::C " << x << std::endl; }
};

int main()
{
  InheritFrom_IntConstructor< boost::mpl::vector<A, B, C> >(1);
}

元函数InheritFrom_IntConstructor 可以泛化为接受任意类型作为构造函数参数,我不确定是否可以泛化为接受任意数量的参数。

【讨论】:

  • @Begeoth:完美运行。不过,我需要看看 fold 到底做了什么,但非常感谢!
  • @Armen: mpl::fold 几乎和我在解决方案中所做的完全一样。
【解决方案2】:

这样的?

template <typename ...BaseClasses>
class Aggregator : public BaseClasses...
{
public:
    Aggregator(int i) : BaseClasses(i)...
    {}

};

使用示例:

Aggregator<U, V, W> a(10);
Aggregator<U, V> b(15);
Aggregator<W> c(20);

注意:它使用可变参数模板,所以需要 C++11。

【讨论】:

  • +1:这非常干净和简单。谢谢你。不幸的是,不幸我不能使用可变参数模板:(
  • BaseClasses(i)... 这行得通吗? § 14.5.3/5 似乎读到确实如此!整洁!
  • C++11 表现力的好例子。我想将原始问题概括为任意数量的任意类型构造函数参数。
  • @Mooing Duck:实际上这对我来说是一个全新的论点,我没有真正检查标准,g++ 接受了它,我认为它是正确的。 :p
【解决方案3】:

我没有使用 Boost,我不确定我的解决方案是否更接近您的需求。但我仍然在发布它:

template<typename typeseq>
struct X : typeseq::head, X<typename typeseq::tail>
{
   typedef typename typeseq::head base;
   typedef X<typename typeseq::tail> recursebase;
   X(int i) : base(i), recursebase(i) {}
   void init(int i) 
   {
       base::init(i);
       recursebase::init(i);
   }
};

template<>
struct X<null_type> 
{
   X(int i) {}
   void init(int i)  { } 
};

然后,测试代码:

typedef typelist<S,typelist<U>> typeseq;
X<typeseq> x(10);
x.init(100);

在线演示:http://ideone.com/e6tuM

【讨论】:

  • 当我看到 Begemoth 的回答时,我也想到了这一点,我正要发布它。不过你的速度更快:D 比我原来的答案更好。
【解决方案4】:

这样的事情应该可以工作:

template<class typeOne>
class X1 : public typeOne
{
    X(int b): typeOne(b)
    {}
};
template<class typeOne, class typeTwo>
class X2 : public typeOne, public typeTwo
{
    X(int b): typeOne(b), typeTwo(b)
    {}
};
template<class typeOne, class typeTwo, class TypeThree>
class X3 : public typeOne, public typeTwo, public typeThree
{
    X(int b): typeOne(b), typeTwo(b), typeThree(b)
    {}
};

或者,如果您愿意为每个对象浪费几个字节,您可以使用占位符,并且只制作一个大的。对于每个实例,每个未使用的基本类型最多应该浪费一个字节。

template<int>
class PlaceHolder { PlaceHolder(int){} };

template<
         class typeOne, 
         class typeTwo=PlaceHolder<2>, 
         class TypeThree=PlaceHolder<3>,
         class TypeFour=PlaceHolder<4>,
         class TypeFive=PlaceHolder<5>
        >
class X : 
         public typeOne, 
         public typeTwo, 
         public typeThree,
         public typeFour,
         public typeFive
{
    X(int b)
    : typeOne(b), 
    typeTwo(b), 
    typeThree(b),
    typeFour(b),
    typeFive(b)
    {}

    X(const X& b)
    : typeOne(b), 
    typeTwo(b), 
    typeThree(b),
    typeFour(b),
    typeFive(b)
    {}

    X& operator=(const X& b) {
        typeOne::operator=(b);
        typeTwo::operator=(b);
        typeThree::operator=(b);
        typeFour::operator=(b);
        typeFive::operator=(b);}
        return *this;
    }
};

【讨论】:

  • 您不能拥有具有不同模板参数编号的相同模板
  • 好的,更改了模板名称,并添加了一个只能使用一个名称的版本,但可能会浪费空间。
  • 我真的不喜欢你的解决方案,但我赞成它,因为你花时间试图帮助我。谢谢
  • 老实说,我也不喜欢我的解决方案。 :D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-23
  • 1970-01-01
  • 1970-01-01
  • 2012-02-13
  • 1970-01-01
  • 2013-02-12
  • 1970-01-01
相关资源
最近更新 更多