有没有可能写一个CRTP类,在一个类中添加一个成员,只有当一个同名的成员不存在时(在C++17中)?
template<class C> using require_foo = ...;
struct Foolish : require_foo<Foolish> {
int foo;
}; // contains just one foo, CRTP is an empty base
struct NotFoolish : require_foo<NotFoolish> {
}; // contains just one foo, provided by CRTP base
我试了显而易见的方法:
#include <type_traits>
void has_foo_helper(...);
template<class Class>
auto has_foo_helper(Class* obj) -> decltype(obj->foo);
template<class Class>
constexpr bool has_foo =
std::is_same_v<decltype(has_foo_helper(std::declval<Class*>())), int>;
template<class, bool>
struct require_foo_impl;
template<class Class>
struct require_foo_impl<Class, false> {
};
template<class Class>
struct require_foo_impl<Class, true> {
int foo;
};
template<class Class>
using require_foo = require_foo_impl<Class, has_foo<Class>>;
但它不起作用:
static_assert(has_foo<Foolish>); // failed due to requirement 'has_foo<Foolish>'
static_assert(has_foo<NotFoolish>); // failed due to requirement 'has_foo<NotFoolish>'
想想看,has_foo
似乎是自相矛盾的:如果一个类没有foo
,它会添加它,但是现在这个类有了foo
,所以它不会添加它,等等。
所以我对解决方案的存在持悲观态度,但我希望被证明是错误的。
1条答案
按热度按时间uoifb46i1#
在C中没有解决方案,也不太可能有一个。
最根本的问题是
Foolish
和NotFoolish
的定义在它们的右括号之前是不完整的,并且它们需要从一个超类继承,而这个超类需要有一个从它继承的类的完整定义。没有一个完整的定义,就不可能通过CRTP、SFINAE或任何其他技术来确定。而超类必须有一个完整的定义,在任何继承自它的类的定义都是完整的之前。鸡与蛋的问题在C中根本无法解决。