ValueTree::isEmpty()

would be handy to have something like :

bool ValueTree::isEmpty() const
{
    return ! (getNumProperties() > 0 || getNumChildren() > 0);
}

You can compare a ValueTree to a default constructed one, which will be empty:

if (m_tree.isEquivalentTo (juce::ValueTree{}))
{
    // m_tree is empty
}

Not as readable as isEmpty() thought tbf.

that wouldn’t work, because an empty value tree with a type name is not equivalent to a non-valid default constructed tree.

The docs of isEquivalentTo() say:

Performs a deep comparison between the properties and children of two trees.

If all the properties and children of the two trees are the same (recursively), this returns true. The normal operator==() only checks whether two trees refer to the same shared data structure, so use this method if you need to do a proper value comparison.

Which I took to mean it doesn’t compare the trees’ types. I didn’t test it tbh so I may be wrong.

You could always pass m_tree.getType() to the constructor of the temp tree.

Looks like types are compared actually, my bad:

so then how about

static inline bool isValueTreeEmpty (const ValueTree& tree)
{
    return tree.isEquivalentTo (ValueTree {tree.getType()});
}

??

That would surely fix the wrong type comparison, but why would you want to do a comparison that you are not interested in and that you know it would succeed (because you rigged it in the first place)?

Just use the version the OP @lalala gave.
The only question is, if the framework authors think that is a valuable addition or bloat. I can see arguments for both.

But luckily it is easy enough to use it as free function, so no need to search for workarounds.