Hello! I’m the madman
JUCE has added final
to certain classes like String
. It inhibits inheriting from the class. This has broken some of my code, and I haven’t yet found a way to work around it. At the ADC’17 JUCE clinic, I showed an example. @jules, @fabian and I didn’t find a solution straight away, and decided to put it on the forum.
If you can find a solution to the problem below, I’ll buy you a beer
I have a class called any
. It’s similar to std::any
or boost::any
in that you can put any object into it, it forgets the type, and you can get the object back later on:
any greeting(String("Hello World!"));
// ...
String extracted = greeting.get<String>();
Why not just use std::any
? Because I need this:
class Animal {};
class Cat : public Animal {};
any cat((Cat()));
Animal a = cat.get<Animal>();
I need to put in instances of a subclass, and extract just the base part. std::any
and boost::any
don’t do this.
The any
class (simplified):
class any {
public:
template<typename T>
explicit any(const T& value)
: wrapped(std::make_shared<Wrapped<T>>(value))
{}
template<typename T>
T get() const
{
if (auto ptr = std::dynamic_pointer_cast<T>(wrapped))
return *ptr;
throw /* type mismatch error */;
}
private:
struct WrappedBase {
virtual ~WrappedBase() {}
};
template<typename T>
struct Wrapped : WrappedBase, T {
Wrapped(const T& u) : T(u) {}
};
std::shared_ptr<WrappedBase> wrapped;
};
By inheriting from T
, it can leverage dynamic_cast
's upcasting behavior. The Animal
/Cat
example now works, but the String
doesn’t, as String
is final
. If we don’t inherit from T
, how can get()
know whether classes are related?
How do we get both examples to work? All ideas and questions are welcome.