There is no good option for unnamed columns in crossing. Everything gives something undesirable. You can get what you want if you write your own function but its too much work compared to how easy expand.grid is to use. One possibility is to allow .name.repair to accept a prefix so that one could just write name.repair = "V" or maybe it could just default to that.
library(tidyr)
L <- list(0:1, 0:1, 0:1)
V <- function(x) paste0("V", seq_along(x))
crossing(!!!L, .name_repair = V)
expand.grid(L)
There is no good option for unnamed columns in crossing. Everything gives something undesirable. You can get what you want if you write your own function but its too much work compared to how easy expand.grid is to use. One possibility is to allow .name.repair to accept a prefix so that one could just write name.repair = "V" or maybe it could just default to that.