我正在尝试创建一个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);
}
答案 0 :(得分: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> {};
这当然不会抓到孙子。
答案 1 :(得分: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'时,你必须处理混乱的编译器错误。
让我考虑一下。也许我很快会有更好的解决方案;)
编辑: 好的,我更喜欢以下解决方案:
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))>();
}
};
请注意,您需要在“protected”部分中为base-class定义默认构造函数。如果不这样做,对成员函数的调用可能会引发访问冲突,因为它可能会访问未分配的内存。声明“base”类型的对象是不安全的。