Yes. I don't understand the Visual C++ 2019 bug though. Needs renaming
of template parameter for the base class, otherwise fails to compile.
It compilers fine with g++ without such renaming.
#include <assert.h> // assert
#include <type_traits> // std::is_base_of_v
#include <memory> // std::(make_shared, shared_ptr, unique_ptr)
#include <typeinfo>
#include <utility> // std::forward
namespace cppx {
using
std::forward,
std::shared_ptr, std::make_shared, std::static_pointer_cast,
std::unique_ptr;
template< class Derived, class Base >
constexpr bool is_derived_and_base = std::is_base_of_v<Base,
Derived>; // (sic!)
struct Void { virtual ~Void() = default; };
template< class Derived, class Base_param = Void >
class With_cloning_
: public Base_param
{
using Base = Base_param; // Visual C++ 2019 compiler bug
workaround.
auto self() const
-> const Derived&
{
static_assert( is_derived_and_base<Derived, With_cloning_>,
"!" );
return *static_cast<const Derived*>( this );
}
// At this point the inheritance is not known so a covariant
type can't be used.
virtual auto vclone() const
-> Void*
{
assert( typeid( *this ) == typeid( Derived ) );
return new Derived( self() );
}
virtual auto shared_vclone() const
-> shared_ptr<Void>
{
assert( typeid( *this ) == typeid( Derived ) );
return make_shared<Derived>( self() );
}
public:
auto clone() const
-> unique_ptr<Derived>
{ return unique_ptr<Derived>( static_cast<Derived*>( vclone() )
); }
auto shared_clone() const
-> shared_ptr<Derived>
{ return static_pointer_cast<Derived>( shared_vclone() ); }
using Base_class = Base;
template< class... Args >
With_cloning_( Args&&... args ):
Base_class( forward<Args>( args )... )
{}
};
} // namespace cppx
namespace herb {
using cppx::With_cloning_;
struct B:
With_cloning_<B>
{
int m_value;
B( const int v ): m_value( v ) {}
};
struct C:
With_cloning_<C, B>
{
using Base = With_cloning_<C, B>;
C( const int v ): Base( v ) {}
};
struct D:
With_cloning_<D, C>
{
using Base = With_cloning_<D, C>;
D( const int v ): Base( v ) {}
};
void example()
{
using std::make_shared, std::shared_ptr;
shared_ptr<B> b1 = make_shared<D>( 42 );
shared_ptr<B> b2 = b1->clone();
shared_ptr<B> b3 = b1->shared_clone();
assert( b2->m_value == 42 );
assert( b3->m_value == 42 );
assert( typeid( *b1 ) == typeid( D ) );
assert( typeid( D ) == typeid( *b2 ) );
assert( typeid( D ) == typeid( *b3 ) );
}
} // namespace
auto main() -> int
{
herb::example();
}
- Alf