CachedValue<T> with ReferenceCoutedObject that's an abstract class?

Let’s say I have a pure virtual class:

class MyOwnClass : public juce::ReferenceCountedObject
{
// …stuff goes here…
};

And I want to use what ever classes I might inherit from that class with ValueTree’s CachedValue:

CachedValue p_data;

Is that possible? The compiler complains about the class being abstract class, which it obviously should be. It doesn’t help if I try to specify CachedValue<MyOwnClass*>.

If you look at the way CachedValue is implemented, you’ll see that each CachedValue instance holds two copies of T internally (the ‘current’ and ‘default’ values). It’s only possible to instantiate non-abstract classes in this way. It’s not possible for a CachedValue<T> to hold instances of types derived from T.

Ah OK. Then I’ll use non-abstract classes and create the abstraction by putting different kinds of nodes or properties into the ValueTree and dynamic_casting them.

@reuk would it be worth adding some static asserts for the constraints of T?

e.g.

static_assert (! std::is_abstract<T>::value,
               "CachedValue's type can't be abstract.");
static_assert (std::is_default_constructible<T>::value,
               "CachedValue's type must be default constructible");
2 Likes

Still have a weird problem:


class MyOwnClass : public juce::ReferenceCountedObject;

juce::ReferenceCountedObjectPtr p_object = XXXXXXX;
juce::CachedValue< MyOwnClass > p_data;

p_data = *p_object; // Compiler error gets generated due to this line


ERROR MESSAGE FROM XCODE:
JUCE/modules/juce_core/containers/juce_Variant.h:353:61:
No viable conversion from returned value of type ‘const MyOwnClass’ to function return type ‘juce::var’


How to fix that? I assume I don’t need to figure out how to make my own operators for the class to convert from MyOwnClass to var or something? I have created these for MyOwnClass:

MyOwnClass();
MyOwnClass(const juce::var source);
MyOwnClass(const MyOwnClass& r_source);
~MyOwnClass();
MyOwnClass& operator = (const MyOwnClass& r_source);
bool operator != (const MyOwnClass& r_source) const;

You need to write a specialisation for juce::VariantConverter to convert your custom type to a juce::var and vice versa.

namespace juce
{
    template<>
    struct VariantConverter<MyOwnClass>
    {
        static juce::var toVar (const MyOwnClass& myObj)
        {
            return ...;
        }

        static MyOwnClass fromVar (const juce::var& v)
        {
            return ...;
        }
    };
} // namespace juce

What’s the philosophy behind those two methods? Is the idea that they clone all the data from inside the source instance? Or is the idea that if there are CachedValue’s there, both instances (source and the result) should use the exact same references to the data?

EDIT: I just realised MyOwnClass doesn’t have CachedValues in there so the above question should actually be:

var constructor wants ReferenceCountedObject* as a parameter. I assume for this particular case I simply give it the original MyOwnClass instead of cloning it?

juce::CachedValue doesn’t know how to serialise/deserialise any custom classes so you need to provide your own serialisation and deserialisation methods. The way to do that is to write a specialisation of juce::VariantConverter for your custom type.

Yes, you can construct a juce::var from a pointer to a juce::ReferenceCountedObject. For an object derived from that, you can simply use juce::var {&myRefCountedObj}. You’d still need to provide a template specialisation for juce::VariantConverter in order to do that though.

Thank you! It seems to work now.

1 Like