CRTP编译检测与模板组成

时间:2016-02-28 14:02:36

标签: c++ templates c++11

我几天都遇到模板问题,你一次解决我的每一个问题,所以提前谢谢你。

所以我有一个关注uml composition的模板(tl2)和另一个uml composed的模板composed 因此,如果derived对象不是tl2 typename Dtl1 derived不是#include <type_traits> #include <list> #include <string> template <typename T, typename C> class tl2 ; template <typename D, typename T> class tl1 { private: static_assert(std::is_base_of<tl2<T, D>, T>::value, "T should inherit from tl2"); std::list<T> mTs ; tl1() {} ; friend D ; public: T & getTbyName() const ; }; template <typename T, typename C> class tl2 { //static_assert(std::is_base_of<tl1<C, T>, C>::value, "D should inherit from Database"); public: std::string getName() { return mName ; } private: C & mC ; std::string mName ; }; class cl1 ; class cl2 : public tl2<cl2, int> { }; class cl1 : public tl1<int, cl2> { }; ,我的目标是不进行编译。

关注此post并在此one的帮助下,我得到了以下代码:

D

我的问题是编译得非常好,我不想。 我不想编译,因为来自tl1<D, T>的{​​{1}}必须derived来自tl1。 实际上class cl1 : public tl1<int, cl2>不正确,但它编译。那么为什么呢? 如果我将cl1更改为:

,则无法编译
class cl1 : public tl1<int, cl2>  {    
    cl1() {}
};

我理解为什么它在更改后没有编译,但我不明白为什么它在之前编译。

事实是tl1tl2将在库中,所以我想在库中执行所有检查。我无法控制派生,所以我想确保implementationtlX derived

再次感谢您的时间 昆汀

2 个答案:

答案 0 :(得分:1)

执行您要执行的操作的问题是周期性依赖性。 std::is_base_of需要一个完整的类型才能在我所知的范围内工作。

您的代码在tl1 ..

中有两个限制
  • T必须继承自tl2
  • D必须继承自tl1

最后,它最终看起来像:

tl1<T, D>其中D继承tl1<T, D>,其中D继承tl1<T, D>

换句话说,永远不会定义D,因为Tl1需要将D定义为模板参数,但D必须从需要它的Tl1继承。

现在,如果删除对D的限制,则以下代码将按原样编译,因为满足第一个限制。但是,如果取消注释tl1中的static_assert,它将永远不会编译,因为D的定义取决于tl1的定义,这取决于D的定义,依此类推......等等。

您会收到如下错误:

invalid use of incomplete type 'class cl1'
     struct is_base_of
            ^
note: forward declaration of 'class cl1'

代码:

#include <type_traits>
#include <list>
#include <string>

template <typename T, typename C>
class tl2 ;

template <typename D, typename T>
class tl1 {
private:
    static_assert(std::is_base_of<tl2<T, D>, T>::value, "T should     inherit from tl2");
    //static_assert(std::is_base_of<tl1, D>::value, "D should inherit from tl1");
    std::list<T> mTs ;
    friend D ;
public:
    tl1() {}
    T & getTbyName() const ;
};

template <typename T, typename C>
class tl2 {
    //static_assert(std::is_base_of<tl1<C, T>, C>::value, "D should inherit from Database");
public:
    std::string getName() { return mName ; }
private:
    //C & mC ;
    std::string mName ;
};


class cl1;

class cl2 : public tl2<cl2, cl1>  {
    public:
        cl2() {}
};

class cl1 : public tl1<cl1, cl2>  {
    public:
        cl1() {}
};

int main() {
    cl1 a;
    cl2 b;
    return 0;
}

如果您将std::is_base_of替换为:

template<class B, class D>
struct is_base_of
{
  template<typename T> struct dummy {};
  struct Child : D, dummy<int> {};

  static B* Check (B*);
  template<class T> static char Check (dummy<T>*);

  static const bool value = (sizeof(Check((Child*)0)) == sizeof(B*));
};

它会给你错误:

recursively required by substitution of 'template<class T> static char is_base_of<B, D>::Check(is_base_of<B, D>::dummy<T>*) [with T = <missing>]'

在我看来,对于正在发生的事情更清楚。

TLDR:你不能

答案 1 :(得分:1)

你的代码编译,因为静态断言没有错。

cl1专门用tl1和

T = cl2继承自tl2<cl2, int> D = int

然后你验证

std::is_base_of<tl2<T, D>, T>::value == true

所以我们在这里替换TD

std::is_base_of<tl2<cl2, int>, cl2>::value == true

这是正确的。

换句话说,你的静态断言可能不会检查它应该是什么。截至目前,我有点困惑你想要实现的目标。我会回答你以前的问题,但你应该认真考虑让你的名字更清晰。这将有助于理解你打算实现的目标。

在得到@Brandon的反馈后,我想您可能正在寻找这个:http://ideone.com/H4hm3O