So aside from things stopping compiling, this ValueTreeSynchronizer looks good.  I'll have a go at bolting onto my cross-thread synchronizer to replace my cheap and dirty mechanism later :)


Incidentally - what's the argument for and against implementing them as pure virutal functions rather than virtual functions with an empty body (which would let you choose which you cared about). 

Cheers Jules!

Thanks - it's very new code that's not properly tested yet, so be careful!

In this case it's pure-virtual because there'd be really no point in using the class without implementing that method, so making it pure will make sure the compiler complains if you forget to do so.

I have cases where I just implement one or two of the things, for examples this one which is only interested in property changes on a node: 

    /* ValueTree listeners. */

    void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const Identifier& property) override;

    void valueTreeChildAdded (ValueTree& parentTree, ValueTree& childWhichHasBeenAdded) {}

    void valueTreeChildRemoved (ValueTree& parentTree, ValueTree& childWhichHasBeenRemoved, int) {}

    void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved, int, int) {}

    void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) {}

    void valueTreeRedirected (ValueTree& treeWhichHasBeenChanged)  {}

Sure, but that's the ValueTree::Listener, I thought you were talking about the ValueTreeSynchroniser, which just has one virtual method.

One advantage of having them pure is that in a case like the ValueTree::Listener where I had to change the parameters, it guarantees that everybody will be forced to update their code, and can't accidentally get a silent error when the method they were overloading changes.

Ah, that's true enough ... :) Silent failure would be much worse.  Real head-scratcher.