【问题标题】:CRTP compile detection with template composition带有模板组合的 CRTP 编译检测
【发布时间】:2016-02-28 14:02:35
【问题描述】:

几天以来我一直遇到模板问题,您一次解决了我的每一个问题,所以提前感谢您。

所以我有一个模板 (tl1) 关心 uml composition,另一个模板 (tl2) 就是 uml composed
因此,如果composed 对象不是tl2derived 并且typename D 不是tl1 derived,我的目标是不编译。

按照postone 的帮助,我得到了以下代码:

#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>  {

};

我的问题是这个编译得很好,我不想。 我不想编译,因为来自tl1&lt;D, T&gt;D 必须来自tl1derived
实际上class cl1 : public tl1&lt;int, cl2&gt; 不正确,但它可以编译。那为什么呢?
如果我将cl1 更改为:

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

我明白为什么更改后它不编译,但我不明白为什么它之前编译。

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

再次感谢您的光临。
昆汀

【问题讨论】:

  • "我的问题是这个编译得很好,我不想。"为什么?通常问题是某些东西无法编译,而您希望它能够编译。 “如果我将 cl1 更改为:......” cl1 已按照您的指示定义,并且编译没有任何问题。你的问题不清楚,而且令人困惑。你需要澄清它们。
  • @SamVarshavchik 现在描述更清楚了吗?
  • std::is_base_of&lt;tl2&lt;T, D&gt;, T&gt;::value 检查 T 是否派生自 tl2 但您在哪里检查 std::is_base_of&lt;Tl1, D&gt;::value(D 派生自 Tl1)。
  • @Brandon 我试过了,但它不能编译我认为这是因为tl1class cl1 : public tl1&lt;int, cl2&gt; 中不知道D

标签: c++ templates c++11


【解决方案1】:

做你想做的事情的问题是循环依赖。据我所知,std::is_base_of 需要一个完整的类型才能工作。

您的代码在 tl1..中有两个限制。

  • T 必须继承自 tl2
  • D 必须继承自 tl1

最后,它看起来像:

tl1&lt;T, D&gt; 其中 D 继承 tl1&lt;T, D&gt; 其中 D 继承 tl1&lt;T, D&gt;

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

现在,如果您取消对 D 的限制,那么以下代码将按应有的方式编译,因为满足了第一个限制。但是,如果您取消注释 tl1 中的 static_assert,它将永远不会编译,因为 D 的定义取决于 tl1 的定义,而 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&lt;class T&gt; static char is_base_of&lt;B, D&gt;::Check(is_base_of&lt;B, D&gt;::dummy&lt;T&gt;*) [with T = &lt;missing&gt;]'

在我看来,这对于正在发生的事情要清楚得多。

TLDR:你不能。

【讨论】:

  • 感谢您非常有建设性的回答(以及您的时间)。这就是为什么 tl1 构造函数是私有的。但我不明白为什么class cl1 : public tl1&lt;int, cl2&gt; 不尖叫……
  • @QuentinHuot-Marchand,通常不允许在标准库模板中使用不完整类型,如果这样做,您可能会得到未定义的行为。有一些例外,但是,当您使用任何具有不完整类型的模板时,您不能期望编译器会尖叫——没有办法对模板进行编程,以便在使用不完整类型时生成错误,或者完全检测到这一点。
  • @ChrisBeck 我明白,我想我必须处理这个问题。感谢您的宝贵时间
  • @Brandon 你可以,你只需要推迟检查,直到编译器对类型有足够的了解。请参阅我的答案 [这里] (stackoverflow.com/a/35688195/2173029)。
  • @Brandon 感谢您指出不需要deferred_base_of(我承认,我很惊讶)。不过,我确实回答了这篇文章(它检查了错误的内容)和前一篇文章的问题。关键是推迟检查可以打破循环。在这里看和玩:ideone.com/H4hm3O
【解决方案2】:

您的代码可以编译,因为静态断言没有任何问题。

cl1 用

专门化 tl1

T = cl2 继承自 tl2&lt;cl2, int&gt; 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

【讨论】:

    猜你喜欢
    • 2016-04-16
    • 2018-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-26
    • 2023-04-04
    相关资源
    最近更新 更多