是否有一种“最佳实践”方法来检查(在编译时)多继承关系中的非第一父关系?我用下面的例子来说明我的问题:
此代码是一种允许在多重继承中检查非第一父关系的方法,通过使用在GCC中工作的void指针比较技巧(6.3及以下:7.1及以上版本不允许)但不在clang(5.0.0):
#pragma clang diagnostic ignored "-Wreinterpret-base-class"
#include <cassert>
#include <type_traits>
struct Grandparent {
int thing = 1;
virtual void foo() {};
};
struct Parent1 : Grandparent {
int thing = 2;
};
struct Parent2 : Grandparent {
int thing = 3;
};
struct MIChild : public Parent1, public Parent2 {
int thing = 4;
};
template <typename T1, typename T2>
class IsSameVoidPtr
{
static constexpr T1* _p = nullptr;
static constexpr bool Castable(std::true_type)
{
return static_cast<void*>(_p + 1) == static_cast<void*>(static_cast<T2*>(_p + 1));
}
static constexpr bool Castable(std::false_type) { return false; }
public:
static constexpr bool value = Castable(std::integral_constant<bool,
std::is_base_of<T1, T2>{} || std::is_base_of<T2, T1>{}>{});
};
int main() {
MIChild test;
Grandparent* gp_ptr = reinterpret_cast<Grandparent*>(&test);
Parent1* p1_ptr = reinterpret_cast<Parent1*>(&test);
Parent2* p2_ptr = reinterpret_cast<Parent2*>(&test);
MIChild* ch_ptr = &test;
static_assert(IsSameVoidPtr<Parent1, Grandparent>::value == true, "Failed P1 to G test");
static_assert(IsSameVoidPtr<Parent2, Grandparent>::value == true, "Failed P2 to G test");
static_assert(IsSameVoidPtr<Parent1, Parent2>::value == false, "Failed P1 to P2 test");
static_assert(IsSameVoidPtr<MIChild, Parent1>::value == true, "Failed C to P1 test");
static_assert(IsSameVoidPtr<MIChild, Parent2>::value == false, "Failed C to P2 test");
}
GCC编译它并按预期工作。它正确地看到第二个父项具有与子项以及第一个父项不同的void指针。
然而,clang不允许对空指针进行算术运算,这会导致整个错误链(我显示错误的第一个实例,其他错误都是相似的):
32 : <source>:32:27: error: constexpr variable 'value' must be initialized by a constant expression
static constexpr bool value = Castable(std::integral_constant<bool,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42 : <source>:42:19: note: in instantiation of template class 'IsSameVoidPtr<Parent1, Grandparent>' requested here
static_assert(IsSameVoidPtr<Parent1, Grandparent>::value == true, "Failed P1 to G test");
^
28 : <source>:28:38: note: cannot perform pointer arithmetic on null pointer
return static_cast<void*>(_p + 1) == static_cast<void*>(static_cast<T2*>(_p + 1));
^
32 : <source>:32:35: note: in call to 'Castable({})'
static constexpr bool value = Castable(std::integral_constant<bool,
^