Use apply when you don't know what the individual arguments are, or how many there are. You can use funcall (or apply) when you do know that.
For example, suppose your list of args to apply the function to is the value of variable foo. Then you would use (apply 'some-fun foo).
If you know that you're going to apply the function to args 3, toto, and 4, in ...
(advice-add #'undo-tree :filter-return #'undo-tree-advice-history-save-file-name)
This advises the function undo-tree, whereas the defadvice form advises undo-tree-make-history-save-file-name. The equivalent advice-add would be
(advice-add 'undo-tree-make-history-save-file-name :filter-return #'undo-tree-advice-history-save-file-name)
Not exactly. Function buffer-substring requires two arguments. Function - will accept a single argument, but in that case it just returns the negative of that numeric argument. What you want to do is, in effect, apply such functions to a list of arguments. You can use higher-order function apply to do that.
What you can do, if you want, is have a macro or ...