-
September 6th, 2014, 06:48 AM
#1
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
-
September 6th, 2014, 07:24 AM
#2
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
-
September 6th, 2014, 08:04 AM
#3
Re: Templated upcast function
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)
-
September 6th, 2014, 12:30 PM
#4
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.
-
September 7th, 2014, 03:01 AM
#5
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;
}
-
September 7th, 2014, 03:31 AM
#6
Re: Templated upcast function
Originally Posted by 2kaud
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
-
September 7th, 2014, 03:46 AM
#7
Re: Templated upcast function
Originally Posted by PredicateNormative
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
-
September 7th, 2014, 05:01 AM
#8
Re: Templated upcast function
Originally Posted by JohnW@Wessex
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.
-
September 7th, 2014, 05:52 AM
#9
Re: Templated upcast function
The type checks are now all compile time. It was a fairly simple exercise in the end.
Originally Posted by razzle
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
-
September 8th, 2014, 08:10 AM
#10
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)
-
September 8th, 2014, 10:17 AM
#11
Re: Templated upcast function
Originally Posted by OReubens
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
-
September 8th, 2014, 10:52 AM
#12
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|