延迟成员变量类型定义,直到另一个类继承它

时间:2015-06-04 19:03:35

标签: c++ templates c++14 crtp stdtuple

我试图将成员变量类型声明为派生类控制的东西,而不将类型转换为模板。

#include <tuple>
#include <iostream>  
#include <ostream>
using namespace std;

template<class DERIVED_TYPE>
struct haveChildren
{   
    const std::tuple<int, DERIVED_TYPE::innerContext > myChildren;

    haveChildren(int a, char b) : myChildren(5, DERIVED_TYPE::innerContext{ a, b }) {}

    friend ostream& operator<< (ostream& streamReceiver, const haveChildren<DERIVED_TYPE>& streamSender)
    {
        int myInt;  int myChar;
        std::tie(myInt, myChar) =   std::get<1>(streamSender.myChildren);

        return streamReceiver << "My int is " << myInt << " my char is " << ((char)myChar);
    }
};

struct haveChildrenCharAndInt : public haveChildren<haveChildrenCharAndInt>
{
    typedef    std::tuple<char, int> innerContext;

    haveChildrenCharAndInt() : haveChildren<haveChildrenCharAndInt>(10,'x') {}
};

int main(int argc, char* argv[])
{
    cout << haveChildrenCharAndInt();
    return 0;
}

这当然不能编译 - 但我希望你明白我想做什么。

可以通过将类型转换为模板参数来完成,如下所示:

template<class DERIVED_TYPE,typename A,typename B>
struct haveChildren
{   
    const std::tuple<int, std::tuple<A, B>  > myChildren;

    haveChildren(int a, char b) : myChildren(5, std::tuple<A, B> { a, b }) {}

    friend ostream& operator<< (ostream& streamReceiver, const haveChildren<DERIVED_TYPE,A,B>& streamSender)
    {
        int myInt;  int myChar;
        std::tie(myInt, myChar) =   std::get<1>(streamSender.myChildren);

        return streamReceiver << "My int is " << myInt << " my char is " << ((char)myChar);
    }
};

struct haveChildrenCharAndInt : public haveChildren<haveChildrenCharAndInt,char,int>
{
    typedef    std::tuple<char, int> innerContext;

    haveChildrenCharAndInt() : haveChildren<haveChildrenCharAndInt,char,int>(10,'x') {}
};

int main(int argc, char* argv[])
{    
    cout << haveChildrenCharAndInt();
    return 0;
}

但是这个解决方案并不好,因为类应该具有作为成员变量的类型是类,并且它们是在之后创建的。

你们是否知道一个设计或技巧可以使一个类型的成员变量在类继承之前没有定义 - 而不将类型转换为模板参数?

2 个答案:

答案 0 :(得分:1)

您可以稍微改变您的设计并使其发挥作用。

#include <tuple>
#include <iostream>  
#include <ostream>
using namespace std;

// A helper class template to let you define the inner
// context of a derived type before the derived type is
// defined.
template <class DERIVED_TYPE> struct InnerContext;

template<class DERIVED_TYPE>
struct haveChildren
{   
   // Use the helper class template to get the inner context 
   // type of DERIVED_TYPE.
   using DerivedInnerContext = typename InnerContext<DERIVED_TYPE>::type;
   std::tuple<int, DerivedInnerContext> myChildren;

   haveChildren(int a, char b) : myChildren(5, DerivedInnerContext{ a, b }) {}

   friend ostream& operator<< (ostream& streamReceiver, const haveChildren& streamSender)
   {
      int myInt;  int myChar;
      std::tie(myInt, myChar) =  std::get<1>(streamSender.myChildren);

      return streamReceiver << "My int is " << myInt << " my char is " << ((char)myChar);
   }
};

// Define the inner context of haveChildrenCharAndInt before
// haveChildrenCharAndInt is defined.
struct haveChildrenCharAndInt;
template <> struct InnerContext<haveChildrenCharAndInt>
{
   using type = std::tuple<char, int>;
};

// haveChildrenCharAndInt is now simplified.
struct haveChildrenCharAndInt : public haveChildren<haveChildrenCharAndInt>
{
   haveChildrenCharAndInt() : haveChildren<haveChildrenCharAndInt>(10,'x') {}
};

int main(int argc, char* argv[])
{
   cout << haveChildrenCharAndInt();
   return 0;
}

答案 1 :(得分:1)

您可以将内部上下文作为类型特征传递:

template<typename Type>
struct inner_context;

并在基类中使用它:

template<class Derived>
struct base {
    using children_type = typename inner_context<Derived>::type;
    const std::tuple<int, children_type> children;

    base(int a, char b) : children(5, children_type{ a, b }) {}
};

然后,无论何时定义新类型,都要声明该类型的特化:

struct derived;

template<>
struct inner_context<derived> {
    using type = std::tuple<char, int>;
};

最后是类型本身:

struct derived : public base<derived> {
    derived() : base(10,'x') {}
};

Live demo