【问题标题】:Determining if a type is derived from a CRTP base class确定类型是否派生自 CRTP 基类
【发布时间】:2011-02-22 00:43:32
【问题描述】:

我正在尝试创建一个 is_foo 函数,然后我可以将其与 enable_if 一起使用,以确定一个类型是否派生自某个 CRTP 基类。下面的代码是我尝试实现is_foo 函数,但它实际上不起作用。有人能告诉我我需要改变什么来修复它吗?

谢谢。

#include <iostream>
#include <type_traits>
#include <functional>

using namespace std;

template <class Underlying, class Extra>
struct Foo
{
    int foo() const { return static_cast<const Underlying*>(this)->foo(); }
};

template<class T>
struct Bar : Foo<Bar<T>, T>
{
    int foo() const { return 42; }
};

template<class T>
struct is_foo { static const bool value = false; };

template<class Underlying, class Extra>
struct is_foo<Foo<Underlying, Extra> > { static const bool value = true; };

template<class T>
void test(const T &t)
{
    cout << boolalpha << is_foo<T>::value << endl;
}

int main()
{
    Bar<int> b;
    test(b);
}

【问题讨论】:

    标签: c++ crtp


    【解决方案1】:

    将 typedef 添加到 Foo 基础:

    template < typename Derived >
    struct crtp
    {
      ...
      typedef int is_crtp;
    };
    

    实施 has_field 检查:

    BOOST_MPL_HAS_XXX(is_crtp)
    

    实现你的元函数:

    template < typename T >
    struct is_crtp_derived : has_is_crtp<T> {};
    

    这是我能想到的唯一能正确抓住孙子的方法。虽然它很容易出现误报,所以你会想要选择你的名字太讨厌而不能在其他地方意外使用。您的另一个选择是根据 is_base_of 实现您的元函数:

    template < typename T >
    struct is_crtp_derived : std::is_base_of< crtp<T>, T> {};
    

    这当然不会抓到孙子。

    【讨论】:

      【解决方案2】:

      你可以这样做:

      typedef char (&yes)[1];
      typedef char (&no )[2];
      
      
      template<class container>
      struct class_helper
      {
          template<typename member> static no  has_implemented(member);
          template<typename member> static yes has_implemented(member container::*);  
      };
      
      
      template<class derived>
      class base
      {
      protected:
          base() {}
      
      public:
          void foo() 
          {
              static_assert(
                  sizeof(class_helper<derived>::has_implemented(&derived::foo)) == sizeof(yes),
                  "derived::foo not implemented"
              );
              static_cast<derived*>(this)->foo();
          }
      };
      

      但是您需要为您定义的每个接口函数执行 static_assert。可以使用 enable_if 使其更通用:

      static_cast<typename enable_if_c<
          sizeof(class_helper<derived>::has_member(&derived::foo)) == sizeof(yes), derived
      >::type*>(this)->foo();
      

      这种技术带来的缺点是,当 'foo' 未在 'derived' 中实现时,您必须处理令人困惑的编译器错误。

      让我考虑一下。也许我很快就会对这种情况有更好的解决方案;)

      编辑: 好的,我更喜欢以下解决方案:

      template<class derived>
      class base
      {
          template<std::size_t n> struct test {
              static_assert(n != sizeof(no), "derived doesn't implement used interface method");
          };
      
      protected:
          base() {}
      
      public:
          void bar()
          {        
              static_cast<derived*>(this)->bar();
              test<sizeof(class_helper<derived>::has_implemented(&derived::bar))>();
          }
      };
      

      请注意,您需要在“受保护”部分定义基类的默认构造函数。如果不这样做,对成员函数的调用可能会引发访问冲突,因为它可能会访问未分配的内存。声明“base”类型的对象是不安全的。

      【讨论】:

        猜你喜欢
        • 2021-10-25
        • 2011-08-25
        • 2015-03-26
        • 1970-01-01
        • 2019-08-27
        • 1970-01-01
        • 1970-01-01
        • 2011-06-01
        • 1970-01-01
        相关资源
        最近更新 更多