diff --git a/include/boost/type_traits/is_virtual_base_of.hpp b/include/boost/type_traits/is_virtual_base_of.hpp index 84cb355..1321f22 100644 --- a/include/boost/type_traits/is_virtual_base_of.hpp +++ b/include/boost/type_traits/is_virtual_base_of.hpp @@ -1,4 +1,5 @@ // (C) Copyright Daniel Frey and Robert Ramey 2009. +// (C) Copyright Balint Cserni 2017 // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt). @@ -9,7 +10,6 @@ #define BOOST_TT_IS_VIRTUAL_BASE_OF_HPP_INCLUDED #include -#include namespace boost { namespace detail { @@ -22,70 +22,34 @@ namespace detail { #pragma GCC system_header #endif -template +template struct is_virtual_base_of_impl { - BOOST_STATIC_CONSTANT(bool, value = false); -}; + template + struct can_cast + { + typedef char YES; + typedef struct { char x[2]; } NO; -template -struct is_virtual_base_of_impl -{ - union max_align - { - unsigned u; - unsigned long ul; - void* v; - double d; - long double ld; -#ifndef BOOST_NO_LONG_LONG - long long ll; -#endif - }; -#ifdef __BORLANDC__ - struct boost_type_traits_internal_struct_X : public virtual Derived, public virtual Base - { - boost_type_traits_internal_struct_X(); - boost_type_traits_internal_struct_X(const boost_type_traits_internal_struct_X&); - boost_type_traits_internal_struct_X& operator=(const boost_type_traits_internal_struct_X&); - ~boost_type_traits_internal_struct_X()throw(); - max_align data[4]; - }; - struct boost_type_traits_internal_struct_Y : public virtual Derived - { - boost_type_traits_internal_struct_Y(); - boost_type_traits_internal_struct_Y(const boost_type_traits_internal_struct_Y&); - boost_type_traits_internal_struct_Y& operator=(const boost_type_traits_internal_struct_Y&); - ~boost_type_traits_internal_struct_Y()throw(); - max_align data[4]; - }; -#else - struct boost_type_traits_internal_struct_X : public Derived, virtual Base - { - boost_type_traits_internal_struct_X(); - boost_type_traits_internal_struct_X(const boost_type_traits_internal_struct_X&); - boost_type_traits_internal_struct_X& operator=(const boost_type_traits_internal_struct_X&); - ~boost_type_traits_internal_struct_X()throw(); - max_align data[16]; - }; - struct boost_type_traits_internal_struct_Y : public Derived - { - boost_type_traits_internal_struct_Y(); - boost_type_traits_internal_struct_Y(const boost_type_traits_internal_struct_Y&); - boost_type_traits_internal_struct_Y& operator=(const boost_type_traits_internal_struct_Y&); - ~boost_type_traits_internal_struct_Y()throw(); - max_align data[16]; - }; -#endif - BOOST_STATIC_CONSTANT(bool, value = (sizeof(boost_type_traits_internal_struct_X)==sizeof(boost_type_traits_internal_struct_Y))); -}; + // C-style casts have the power to ignore inheritance visibility while still act as a static_cast. + // They can also fall back to the behaviour of reinterpret_cast, which allows is_virtual_base_of to work on non-class types too. + // Note that because we are casting pointers there can be no user-defined operators to interfere. + template static YES test(int*); + static NO test(...); -template -struct is_virtual_base_of_impl2 -{ - typedef boost::integral_constant::value && ! boost::is_same::value)> tag_type; - typedef is_virtual_base_of_impl imp; - BOOST_STATIC_CONSTANT(bool, value = imp::value); + BOOST_STATIC_CONSTANT(bool, value = (sizeof(test(nullptr)) == sizeof(YES))); + }; + + // Implementation based on the standard's rules of explicit type conversions. + // A pointer to an object of *derived* class type may be explicitly converted to a pointer to an *unambiguous* *base* class type. + // A pointer to an object of an *unambiguous* *non-virtual* *base* class type may be explicitly converted to a pointer of a *derived* class type. + // Therefore Derived has a virtual base Base if and only if + // (1) a Derived* can be converted to Base* (so the base class is unambiguous, which comes necessarily from virtual inheritance) + // (2) a Base* cannot be converted to Derived* (so the base class is either ambiguous or virtual) + // With both conditions true, Base must be a virtual base of Derived. + // The "is_base_of" is only needed so the compiler can (but is not required to) error out if the types are incomplete. + // This is in league with the the expected behaviour. + BOOST_STATIC_CONSTANT(bool, value = (boost::is_base_of::value && can_cast::value && !can_cast::value)); }; #ifdef BOOST_MSVC @@ -94,7 +58,7 @@ struct is_virtual_base_of_impl2 } // namespace detail -template struct is_virtual_base_of : public integral_constant::value)>{}; +template struct is_virtual_base_of : public integral_constant::value)>{}; template struct is_virtual_base_of : public false_type{}; template struct is_virtual_base_of : public false_type{};