CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12
  1. #1
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Templated upcast function

    I have a templated function that attempts to upcast a type to a specified base class.
    If TBase is a base of T then a simple upcast is performed.
    If TBase is not a base of T then an exception is thrown.

    The downsides of the current inplementation is that at all possible types of T must be polymorphic for dynamic_cast to compile, plus the fact that I have to use dynamic_cast at all.
    In theory, the dynamic_cast is unecessary as any types which pass the std::is_base_of test are, by definition, simple upcasts, but the compiler will check the syntax of that branch even though it will never be taken for a non-TBase derived T.

    Any ideas on how this could be improved?

    BTW I can't use any C++11 features that can't be easily reverse engineered in C++03.

    Code:
    template <typename TBase, typename T>
    TBase& DoUpCast(T& t)
    {     
      if (std::is_base_of<TBase, T>::value)
      {
        return dynamic_cast<TBase&>(t);
      }
      else
      {
        throw VariantNotABaseTypeException();
      }
    }
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  2. #2
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Templated upcast function

    I think I'm close to a solution, but for a (for the moment) puzzling compiler error.

    Code:
    template <typename TBase, typename T, const bool IsBase>
    struct DoIt;
    
    template <typename TBase, typename T>
    struct DoIt<TBase, T, true>
    {
      TBase& operator()(T& t)
      {
        return t;
      }
    };
    
    template <typename TBase, typename T>
    struct DoIt<TBase, T, false>
    {
      TBase& operator()(T& t)
      {
        throw VariantNotABaseTypeException();
      }
    };
    
    template <typename TBase, typename T>
    TBase& DoUpCast(T& t)
    {
      DoIt<TBase, T, std::is_base_of<TBase, T>::value> doIt;
    
      return doIt(T& t); //<<<< 'T' Illegal use of this type as an identifier.
    }
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  3. #3
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Templated upcast function

    Code:
    return doIt(T& t);
    why not just
    Code:
    return doIt(t);
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  4. #4
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Templated upcast function

    I think something like this might be simpler

    Code:
    namespace details{
    template <typename TBase, typename T>
    TBase& DoUpCast(T& t,std::true_type)
    {
        return dynamic_cast<TBase&>(t);
    }
    
    template <typename TBase, typename T>
    TBase& DoUpCast(T& t,std::false_type)
    {
        throw VariantNotABaseTypeException();
    }
    }
    
    template <typename TBase, typename T>
    TBase& DoUpCast(T& t)
    {
        return details::DoUpCast(t,std::is_base_of<TBase, T>::type());
    }
    Last edited by superbonzo; September 6th, 2014 at 12:33 PM.

  5. #5
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,164

    Re: Templated upcast function

    Am I missing something? Why wait until runtime to tell the programmer they have done something wrong? Why not just fail at compile time?


    Code:
    template <bool canUpCast>
    struct FailIfCannotUpCast;
    
    template <>
    struct FailIfCannotUpCast<true>{};
    
    template <typename TBase, typename T>
    TBase& DoUpCast(T& t)
    {
      FailIfCannotUpCast<std::is_base_of<TBase, T>::value>();
    
      returnt t;
    }

  6. #6
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Templated upcast function

    Quote Originally Posted by 2kaud View Post
    why not just
    Code:
    return doIt(t);
    Do'h!!
    I must have been a bit overtired when I wrote that bit
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  7. #7
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Templated upcast function

    Quote Originally Posted by PredicateNormative View Post
    Am I missing something? Why wait until runtime to tell the programmer they have done something wrong? Why not just fail at compile time?
    The class it's used in has a variable number of template types. The unused template types default to 'null type' place holders.
    If the check was at compile time then the placeholders fail the test.

    I will probably look at seeing whether further template specialisations can convert this to a purely compile time check.
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  8. #8
    Join Date
    Jul 2013
    Posts
    576

    Re: Templated upcast function

    Quote Originally Posted by JohnW@Wessex View Post
    I will probably look at seeing whether further template specialisations can convert this to a purely compile time check.
    I strongly recommend you review this design.

    If you end up having to turn a type safe upcast into an unsafe downcast for implementation reasons only, something is seriously wrong.

    Why is everybody so hellbent on circumventing type safety, one of the major assets of C++? Beats me.

    All this time consuming fiddling back and forth to "outsmart the compiler". All this brittle and difficult to maintain code being produced that not even the original author understands. If you cannot do it right in a simple and straightforward fashion, don't do it at all.
    Last edited by razzle; September 7th, 2014 at 06:11 AM.

  9. #9
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Templated upcast function

    The type checks are now all compile time. It was a fairly simple exercise in the end.

    Quote Originally Posted by razzle View Post
    I strongly recommend you review this design.
    If you end up having to turn a type safe upcast into an unsafe downcast for implementation reasons only, something is seriously wrong.
    Where are the downcasts? The only casts available to the user are upcasts and they are now all checked at compile time.
    Attempting to cast the variant to a class that is not a base of the polymorphic types that can be stored by the variant is a compile time error.
    There are some 'reinterpret' casts internally, but they are soley to access the internal storage buffer. The user has no access to these.

    The aim of the design was to create a heterogeneous type that enforced virtually all of its type checks at compile time.
    The only runtime exception that can occur is when a type is requested that is not currently contained in the variant, but is supported by the Variant.

    Why is everybody so hellbent on circumventing one of the major assets of C++ all the time
    I'm using the assets of C++ to make sure that they cannot be circimvented by the user of the Variant class.

    If you cannot do it right in a simple and straightforward fashion, don't do it at all.
    Gosh, I wish all engineering problems were that easy!

    All this brittle and difficult to maintain code being produced
    If anyone were to see the internals of the class then I pretty sure they'd find there's nothing that would tax even a half decent C++ programmer who knew their templates.
    The Variant class is a thin wrapper around a generic storage area to produce a 'super' union with all of the type safety that a union hasn't.
    Last edited by JohnW@Wessex; September 7th, 2014 at 08:03 AM.
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  10. #10
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Templated upcast function

    why do you need any code at all ?
    dynamic_cast<>()
    already does what you want. if you upcast it'll typecheck and throw if it's not valid. (you need to enable RTTI)

  11. #11
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Templated upcast function

    Quote Originally Posted by OReubens View Post
    why do you need any code at all ?
    dynamic_cast<>()
    already does what you want.
    But that generates a runtime error.
    With the Variant template class it's a compile time error.
    Last edited by JohnW@Wessex; September 8th, 2014 at 10:21 AM.
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  12. #12
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: Templated upcast function

    Code:
    class Base {};
    class NotBase {};
    class Derived1 : public Base {};
    class Derived2 : public Base {};
    
    
    Variant<Derived1, Derived2> values;
    
    
    Base& base = values;  // Compile fail. Ambiguous conversion.
    
    
    Base& base = values.UpCast<Base>(); // Compile pass.
    
    
    Base& base = values.UpCast<NotBase>(); // Compile fail. Variants are not derived from NotBase.
    Code:
    Variant<Derived1, Derived2, int> values;
    
    
    Base& base = values2.UpCast<Base>(); // Compile fail. 'int' is not derived from Base.
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured