确定类型是否派生自 CRTP 基类

发布于 2024-10-18 09:25:50 字数 937 浏览 8 评论 0原文

我正在尝试创建一个 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);
}

I'm trying to create an is_foo function, that I can then use with enable_if, to determine if a type is derived from a certain CRTP base class. The code below is my attempt at implementing the is_foo function, but it doesn't actually work. Could someone tell me what I need to change to fix it?

Thanks.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一杯敬自由 2024-10-25 09:25:50

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

这当然不会捕获孙子。

Add a typedef to the Foo base:

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

Implement a has_field check:

BOOST_MPL_HAS_XXX(is_crtp)

Implement your metafunction:

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

This is the only way I can think of that will correctly catch grandchildren. It's prone to false positives though so you'll want to pick your names to be too obnoxious to be accidentally used elsewhere. Your other option would be to implement your metafunction in terms of is_base_of:

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

This of course won't catch grandchildren.

难以启齿的温柔 2024-10-25 09:25:50

您可以这样做:

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”未在“衍生”中实现时,您必须处理令人困惑的编译器错误。

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

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

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

You could do it like this:

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();
    }
};

But you need to do the static_assert for each interface function you've defined. It's possible to use enable_if to make it more general:

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

This technique brings the disadvantage, that you have to deal with confusing compiler-errors, when 'foo' isn't implemented in 'derived'.

Let me think about that. Maybe I have some better solution for this case soon ;)

EDIT:
Okay, I would prefer the following solution:

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))>();
    }
};

Please note, that you need to define the default constructor for base-class in 'protected' section. If you don't do this, a call to a member function could raise an access-violation, because it might access memory, which wasn't allocated. It's not safe to declare objects of type 'base'.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文