extend to dereference pointer and take addresses
...since I consider that a comparatively safe convenience feature. Of course we *do perform* a NULL check and throw an exception. So now the actual casting or conversion functions are designed to work always on the same level of references or pointers, which means we can just use the standard conversions of the language. This has the nice effect of ruling out dangerous combinations (like taking a L-ref from a R-ref) automatically
This commit is contained in:
parent
b9aa8033c7
commit
69bf324a1e
2 changed files with 114 additions and 54 deletions
|
|
@ -54,25 +54,22 @@ namespace util {
|
|||
using std::remove_pointer;
|
||||
using std::remove_reference;
|
||||
|
||||
namespace error = lumiera::error;
|
||||
|
||||
template <typename T>
|
||||
using PlainType = typename remove_pointer<
|
||||
typename remove_reference<T>::type>::type;
|
||||
|
||||
template <typename T>
|
||||
struct has_RTTI
|
||||
{
|
||||
using PlainType = typename remove_pointer<
|
||||
typename remove_reference<T>::type>::type;
|
||||
|
||||
static constexpr bool value = std::is_polymorphic<PlainType>::value;
|
||||
static constexpr bool value = std::is_polymorphic<PlainType<T>>::value;
|
||||
};
|
||||
|
||||
template <typename SRC, typename TAR>
|
||||
struct can_downcast
|
||||
{
|
||||
using PlainSRC = typename remove_pointer<
|
||||
typename remove_reference<SRC>::type>::type;
|
||||
using PlainTAR = typename remove_pointer<
|
||||
typename remove_reference<TAR>::type>::type;
|
||||
|
||||
static constexpr bool value = std::is_base_of<PlainSRC, PlainTAR>::value;
|
||||
static constexpr bool value = std::is_base_of<PlainType<SRC>, PlainType<TAR>>::value;
|
||||
};
|
||||
|
||||
template <typename SRC, typename TAR>
|
||||
|
|
@ -88,6 +85,20 @@ namespace util {
|
|||
: std::is_convertible<SRC,TAR>
|
||||
{ };
|
||||
|
||||
template <typename SRC, typename TAR>
|
||||
struct can_take_address
|
||||
{
|
||||
static constexpr bool value = !std::is_pointer<typename remove_reference<SRC>::type>::value
|
||||
&& std::is_pointer<typename remove_reference<TAR>::type>::value;
|
||||
};
|
||||
|
||||
template <typename SRC, typename TAR>
|
||||
struct can_dereference
|
||||
{
|
||||
static constexpr bool value = !std::is_pointer<typename remove_reference<TAR>::type>::value
|
||||
&& std::is_pointer<typename remove_reference<SRC>::type>::value;
|
||||
};
|
||||
|
||||
|
||||
template <typename SRC, typename TAR>
|
||||
struct if_can_use_dynamic_downcast
|
||||
|
|
@ -98,6 +109,16 @@ namespace util {
|
|||
struct if_can_use_conversion
|
||||
: std::enable_if< can_use_conversion<SRC,TAR>::value, TAR>
|
||||
{ };
|
||||
|
||||
template <typename SRC, typename TAR>
|
||||
struct if_can_take_address
|
||||
: std::enable_if< can_take_address<SRC,TAR>::value, TAR>
|
||||
{ };
|
||||
|
||||
template <typename SRC, typename TAR>
|
||||
struct if_can_dereference
|
||||
: std::enable_if< can_dereference<SRC,TAR>::value, TAR>
|
||||
{ };
|
||||
|
||||
|
||||
|
||||
|
|
@ -121,6 +142,26 @@ namespace util {
|
|||
std::cerr << "convert-"<<lib::test::showRefKind<SRC>()<<" && ->"<<lib::test::showRefKind<SRC&&>()<<std::endl;
|
||||
return std::forward<SRC> (elem);
|
||||
}
|
||||
|
||||
template<typename SRC>
|
||||
static typename if_can_take_address<SRC&&,TAR>::type
|
||||
access (SRC&& elem)
|
||||
{
|
||||
std::cerr << "address-"<<lib::test::showRefKind<SRC>()<<" && ->"<<lib::test::showRefKind<SRC&&>()<<std::endl;
|
||||
return AccessCasted<TAR>::access (&elem);
|
||||
}
|
||||
|
||||
template<typename SRC>
|
||||
static typename if_can_dereference<SRC&&,TAR>::type
|
||||
access (SRC&& elem)
|
||||
{
|
||||
std::cerr << "deref-"<<lib::test::showRefKind<SRC>()<<" && ->"<<lib::test::showRefKind<SRC&&>()<<std::endl;
|
||||
if (!elem)
|
||||
throw error::Invalid("AccessCasted: attempt to build a value or reference from a NULL pointer"
|
||||
,error::LUMIERA_ERROR_BOTTOM_VALUE);
|
||||
|
||||
return AccessCasted<TAR>::access (*elem);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ using std::move;
|
|||
using std::string;
|
||||
using std::ostream;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
using lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE;
|
||||
|
||||
|
||||
namespace util {
|
||||
|
|
@ -94,61 +97,77 @@ namespace test {
|
|||
E* pE = &f;
|
||||
D* pDE = pE;
|
||||
|
||||
cout << "can_downcast<B,D> = " << can_downcast<B,D>::value << "\n";
|
||||
cout << "can_downcast<B*,D*> = " << can_downcast<B*,D*>::value << "\n";
|
||||
cout << "can_downcast<B&,D&> = " << can_downcast<B&,D&>::value << "\n";
|
||||
cout << "can_downcast<B&,D*> = " << can_downcast<B&,D*>::value << "\n";
|
||||
cout << "can_downcast<B*,D&> = " << can_downcast<B*,D&>::value << "\n";
|
||||
cout << "can_downcast<B*&,D*&> = " << can_downcast<B*&,D*&>::value << "\n";
|
||||
cout << "can_downcast<D*&,D*&> = " << can_downcast<D*&,D*&>::value << "\n";
|
||||
cout << "can_downcast<B,D> = " << can_downcast<B,D>::value <<endl;
|
||||
cout << "can_downcast<B*,D*> = " << can_downcast<B*,D*>::value <<endl;
|
||||
cout << "can_downcast<B&,D&> = " << can_downcast<B&,D&>::value <<endl;
|
||||
cout << "can_downcast<B&,D*> = " << can_downcast<B&,D*>::value <<endl;
|
||||
cout << "can_downcast<B*,D&> = " << can_downcast<B*,D&>::value <<endl;
|
||||
cout << "can_downcast<B*&,D*&> = " << can_downcast<B*&,D*&>::value <<endl;
|
||||
cout << "can_downcast<D*&,D*&> = " << can_downcast<D*&,D*&>::value <<endl;
|
||||
|
||||
cout << "can_downcast<D*,E*> = " << can_downcast<D*,E*>::value << "\n";
|
||||
cout << "can_downcast<E*,F*> = " << can_downcast<E*,F*>::value << "\n";
|
||||
cout << "can_downcast<D*,E*> = " << can_downcast<D*,E*>::value <<endl;
|
||||
cout << "can_downcast<E*,F*> = " << can_downcast<E*,F*>::value <<endl;
|
||||
|
||||
cout << "has_RTTI<D*> = " << has_RTTI<D*>::value << "\n";
|
||||
cout << "has_RTTI<E*> = " << has_RTTI<E*>::value << "\n";
|
||||
cout << "has_RTTI<F*> = " << has_RTTI<F*>::value << "\n";
|
||||
cout << "has_RTTI<D*> = " << has_RTTI<D*>::value <<endl;
|
||||
cout << "has_RTTI<E*> = " << has_RTTI<E*>::value <<endl;
|
||||
cout << "has_RTTI<F*> = " << has_RTTI<F*>::value <<endl;
|
||||
|
||||
cout << "is_convertible<D,D&> = " << std::is_convertible<D,D&>::value << "\n";
|
||||
cout << "is_convertible<D&,D> = " << std::is_convertible<D&,D>::value << "\n";
|
||||
cout << "is_convertible<D,D&> = " << std::is_convertible<D,D&>::value <<endl;
|
||||
cout << "is_convertible<D&,D> = " << std::is_convertible<D&,D>::value <<endl;
|
||||
|
||||
|
||||
cout << "can_use_dynamic_downcast<D,D&> = " << can_use_dynamic_downcast<D,D&>::value << "\n";
|
||||
cout << "can_use_conversion<D,D&> = " << can_use_conversion<D,D&>::value << "\n";
|
||||
cout << "can_use_dynamic_downcast<B*,D*> = " << can_use_dynamic_downcast<B*,D*>::value << "\n";
|
||||
cout << "can_use_conversion<D*,B*> = " << can_use_conversion<D*,B*>::value << "\n";
|
||||
cout << "can_use_dynamic_downcast<D,D&> = " << can_use_dynamic_downcast<D,D&>::value <<endl;
|
||||
cout << "can_use_conversion<D,D&> = " << can_use_conversion<D,D&>::value <<endl;
|
||||
cout << "can_use_dynamic_downcast<B*,D*> = " << can_use_dynamic_downcast<B*,D*>::value <<endl;
|
||||
cout << "can_use_conversion<D*,B*> = " << can_use_conversion<D*,B*>::value <<endl;
|
||||
|
||||
cout << "can_use_dynamic_downcast<D*&,D*&> = " << can_use_dynamic_downcast<D*&,D*&>::value << "\n";
|
||||
cout << "can_use_conversion<D*&,D*&> = " << can_use_conversion<D*&,D*&>::value << "\n";
|
||||
cout << "can_use_conversion<D*,E*> = " << can_use_conversion<D*,E*>::value << "\n";
|
||||
cout << "can_use_dynamic_downcast<D*&,E*> = " << can_use_dynamic_downcast<D*&,E*>::value << "\n";
|
||||
cout << "can_use_dynamic_downcast<D*&,D*&> = " << can_use_dynamic_downcast<D*&,D*&>::value <<endl;
|
||||
cout << "can_use_conversion<D*&,D*&> = " << can_use_conversion<D*&,D*&>::value <<endl;
|
||||
cout << "can_use_conversion<D*,E*> = " << can_use_conversion<D*,E*>::value <<endl;
|
||||
cout << "can_use_dynamic_downcast<D*&,E*> = " << can_use_dynamic_downcast<D*&,E*>::value <<endl;
|
||||
|
||||
cout << "=== standard case: References ==="<<endl;
|
||||
cout << "Access(D as D&) --->" << AccessCasted<D&>::access(d) <<endl;
|
||||
cout << "Access(D& as D&) --->" << AccessCasted<D&>::access(rD) <<endl;
|
||||
|
||||
cout << "Access(D as D&) --->" << AccessCasted<D&>::access(d) << "\n";
|
||||
cout << "Access(D& as D&) --->" << AccessCasted<D&>::access(rD) << "\n";
|
||||
cout << "Access(D as D) --->" << AccessCasted<D>::access(d) << "\n";
|
||||
cout << "Access(D& as D) --->" << AccessCasted<D>::access(rD) << "\n";
|
||||
cout << "=== build a value object ==="<<endl;
|
||||
cout << "Access(D as D) --->" << AccessCasted<D>::access(d) <<endl;
|
||||
cout << "Access(D& as D) --->" << AccessCasted<D>::access(rD) <<endl;
|
||||
D dd1(d);
|
||||
cout << "Access(D&& as D) --->" << AccessCasted<D>::access(move(dd1)) << "\n";
|
||||
// cout << "Access(B& as D&) --->" << AccessCasted<D&>::access(rB) << "\n";
|
||||
// cout << "Access(D* as D*) --->" << AccessCasted<D*>::access(pD) << "\n";
|
||||
// cout << "Access(B* as D*) --->" << AccessCasted<D*>::access(pB) << "\n";
|
||||
// cout << "Access(D*& as D*&) --->" << AccessCasted<D*&>::access(rpD) << "\n";
|
||||
// cout << "Access(B*& as D*&) --->" << AccessCasted<D*&>::access(rpB) << "\n";
|
||||
cout << "Access(D&& as D) --->" << AccessCasted<D>::access(move(dd1)) <<endl;
|
||||
|
||||
cout << "=== take a pointer ==="<<endl;
|
||||
cout << "Access(D as D*) --->" << AccessCasted<D*>::access(d) <<endl;
|
||||
cout << "Access(D& as D*) --->" << AccessCasted<D*>::access(rD) <<endl;
|
||||
|
||||
cout << "=== dereference a pointer ==="<<endl;
|
||||
cout << "Access(D* as D&) --->" << AccessCasted<D&>::access(pD) <<endl;
|
||||
cout << "Access(D* as D) --->" << AccessCasted<D>::access(pD) <<endl;
|
||||
D* pdd1(pD);
|
||||
cout << "Access(D*&& as D) --->" << AccessCasted<D>::access(move(pdd1)) <<endl;
|
||||
D* pNull(0);
|
||||
VERIFY_ERROR(BOTTOM_VALUE, AccessCasted<D>::access(pNull));
|
||||
|
||||
cout << "=== work cases: actual conversions ==="<<endl;
|
||||
// cout << "Access(B& as D&) --->" << AccessCasted<D&>::access(rB) <<endl;
|
||||
// cout << "Access(D* as D*) --->" << AccessCasted<D*>::access(pD) <<endl;
|
||||
// cout << "Access(B* as D*) --->" << AccessCasted<D*>::access(pB) <<endl;
|
||||
// cout << "Access(D*& as D*&) --->" << AccessCasted<D*&>::access(rpD) <<endl;
|
||||
// cout << "Access(B*& as D*&) --->" << AccessCasted<D*&>::access(rpB) <<endl;
|
||||
//
|
||||
// cout << "Access(D as B&) --->" << AccessCasted<B&>::access(d) << "\n";
|
||||
// cout << "Access(D& as B&) --->" << AccessCasted<B&>::access(rD) << "\n";
|
||||
// cout << "Access(B& as B&) --->" << AccessCasted<D&>::access(rB) << "\n";
|
||||
// cout << "Access(D* as B*) --->" << AccessCasted<B*>::access(pD) << "\n";
|
||||
// cout << "Access(B* as B*) --->" << AccessCasted<B*>::access(pB) << "\n";
|
||||
// cout << "Access(D*& as B*&) --->" << AccessCasted<B*&>::access(rpD) << "\n";
|
||||
// cout << "Access(B*& as B*&) --->" << AccessCasted<B*&>::access(rpB) << "\n";
|
||||
// cout << "Access(D as B&) --->" << AccessCasted<B&>::access(d) <<endl;
|
||||
// cout << "Access(D& as B&) --->" << AccessCasted<B&>::access(rD) <<endl;
|
||||
// cout << "Access(B& as B&) --->" << AccessCasted<D&>::access(rB) <<endl;
|
||||
// cout << "Access(D* as B*) --->" << AccessCasted<B*>::access(pD) <<endl;
|
||||
// cout << "Access(B* as B*) --->" << AccessCasted<B*>::access(pB) <<endl;
|
||||
// cout << "Access(D*& as B*&) --->" << AccessCasted<B*&>::access(rpD) <<endl;
|
||||
// cout << "Access(B*& as B*&) --->" << AccessCasted<B*&>::access(rpB) <<endl;
|
||||
//
|
||||
// cout << "Access(D as E&) --->" << AccessCasted<E&>::access(d) << "\n";
|
||||
// cout << "Access(E& as F&) --->" << AccessCasted<F&>::access(rE) << "\n";
|
||||
// cout << "Access(D(E)* as E*) --->" << AccessCasted<E*>::access(pDE) << "\n";
|
||||
// cout << "Access(D(E)* as F*) --->" << AccessCasted<F*>::access(pDE) << "\n";
|
||||
// cout << "Access(E* as F*) --->" << AccessCasted<F*>::access(pE) << "\n";
|
||||
// cout << "Access(D as E&) --->" << AccessCasted<E&>::access(d) <<endl;
|
||||
// cout << "Access(E& as F&) --->" << AccessCasted<F&>::access(rE) <<endl;
|
||||
// cout << "Access(D(E)* as E*) --->" << AccessCasted<E*>::access(pDE) <<endl;
|
||||
// cout << "Access(D(E)* as F*) --->" << AccessCasted<F*>::access(pDE) <<endl;
|
||||
// cout << "Access(E* as F*) --->" << AccessCasted<F*>::access(pE) <<endl;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue