【问题标题】:Delay a member variables type definition till another class inherits from it延迟成员变量类型定义,直到另一个类从它继承
【发布时间】:2015-06-04 19:03:35
【问题描述】:

我正在尝试将成员变量类型声明为派生类控制的东西 - 而不将类型作为模板传输。

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

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

你们中是否有人知道一种设计或技巧,可以让一个类型的成员变量在类从它继承之前不定义 - 无需将类型作为模板参数传输?

【问题讨论】:

  • 你说的类型......是类并且是之后创建的是什么意思?定义haveChildrenCharAndInt时,构成innerContext的类型需要完整,这样基类才能包含它们的实例。

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


【解决方案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;
}

【讨论】:

  • 非常好,我有一个愿景,认为这样的事情可以奏效——但我无法让它发挥作用。
  • 非常感谢您的帮助
【解决方案2】:

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

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

【讨论】:

  • 我们都是相互联系的,不是吗?
  • 这是迄今为止我所读过的类型特征的最佳解释——我已经阅读了一些示例,但并没有真正理解它,也看不出它在这里是如何工作的。我学到了一项宝贵的技能。非常感谢。
猜你喜欢
  • 2015-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-19
  • 2012-05-16
  • 2014-03-08
相关资源
最近更新 更多