Maintaining The "$@" Interface
If you want shell syntax (compound commands, redirections, etc), you need  to invoke a shell. Thus:
./script.sh bash -c 'ls && clear'
...you'll also need to change $@ to "$@" (unquoted, $@ is exactly the same as -- meaning, has all the bugs of -- $*).
If you want to pass data, do so with extra arguments out-of-band from your code to avoid security bugs:
dir=/tmp # but unlike eval, this is still safe with *any* directory name
./script.sh bash -c 'ls "$1" && clear' _ "$dir"
Unlike  some other approaches, this still lets ./script.sh printf '%s\n' "first line" "second line" work.
Accepting Only One Argument
Using "$@" promises to the user that multiple arguments will be processed; however, eval "$*", like bash -c "$*", discards distinctions between those arguments, whereas bash -c "$@" silently ignores arguments past the first unless the first argument is written with knowledge of that calling convention.
To only accept one argument, and parse it as code, use:
eval "$1"
To only accept the first argument as code, and keep subsequent arguments as $1, $2, etc. in the context of that code, use:
code=$1; shift; eval "$code"