3

我正在尝试创建一个is_foo函数,然后我可以使用 withenable_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);
}
4

2 回答 2

3

将 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> {};

这当然不会抓到孙子。

于 2011-02-22T00:53:38.700 回答
0

你可以这样做:

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”类型的对象是不安全的。

于 2011-04-19T13:35:52.457 回答