简体   繁体   中英

Automatic selection between static_cast and dynamic_cast for best performance

I have to use an object factory that creates new objects of several types each of which is derived from the polymorphic base class. The type of each object is known beforehand, but the factory returns the pointer on the base class. So after construction I need to downcast that pointer to the type of specific object class. In most situation static_cast does its job perfectly, but in the case of virtual inheritance dynamic_cast must be used for downcasting. At the same time I do not want to use dynamic_cast for simple types with not-virtual inheritance from base class due to its run-time overhead.

In other words, I would like to find or make a function that will convert From -type into To -type using static_cast if it is available for this conversion (eg To is not virtually derived from From ) or dynamic_cast otherwise.

Expected use case:

template <typename To, typename From>
To fastest_cast( From && from );

struct A { virtual ~A() = default; };
struct B : A {};
struct C : virtual A {};

int main()
{
    B b;
    fastest_cast<B*>( (A*)&b ); //expected static_cast inside

    C c;
    fastest_cast<C*>( (A*)&c ); //expected dynamic_cast inside
}

Is there anything similar to fastest_cast in std-library or in boost-library? Or it is necessary to implement the conversion function by myself (please suggest how)?

The concept std::derived_from seems to cover the case where you want static_cast , we just have to remove the reference or pointer for it.

template <typename To, typename From>
concept castable = (std::is_pointer_v<To> && std::is_pointer_v<std::remove_cvref_t<From>>) || (std::is_reference_v<To>)

template <typename From, typename To>
concept castable_from = std::derived_from<From, std::remove_cv_t<std::remove_pointer_t<To>>> || std::derived_from<From, std::remove_cvref_t<To>>

template <typename To, castable_from<To> From>
To fastest_cast(From&& from) requires castable<To, From>
{
    return static_cast<To>(from);
}

template <typename To, typename From>
To fastest_cast(From&& from) requires castable<To, From>
{
    return dynamic_cast<To>(from);
}

Here we can use SFINAE approach to check if static_cast is applicable for From -> To conversion. It can be implemented such way:

template<typename ...T>
using void_t = void;

template <typename To, typename From, typename = void>
struct is_static_castable : std::false_type
{
};

template <typename To, typename From>
struct is_static_castable<To, From, void_t<decltype( static_cast<To>( std::declval<From>() ) )>> : std::true_type
{
};

template <typename To, typename From>
constexpr bool is_static_castable_v = is_static_castable<To, From>::value;

after that you can easily write function for type cast using

if constexpr ( is_static_castable_v<To, From> ) :

template<typename To, typename From>
decltype( auto ) fastest_cast( From&& from )
{
    if constexpr ( is_static_castable_v<To, From> )
    {
        return static_cast<To>( std::forward<From>( from ) );
    }
    else
    {
        return dynamic_cast<To>( std::forward<From>( from ) );
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM