The width argument of zoo::rollapply can be a numeric vector.
Hence, in your example, you can use:
rollapply(index, c(1, 3, 5, rep(5, 15), 5, 3, 1), mean)
#  [1] 2.302585 2.350619 2.395822 2.440451 2.483165 2.524124 2.563466 2.601315 2.637779 2.672957 2.706937 2.739798 2.771611 2.802441 2.832347 2.861383
# [17] 2.889599 2.917039 2.943746 2.970195 2.995732
And if n is an odd integer, a general solution is:
w <- c(seq(1, n, 2), rep(n, length(index) - n - 1), seq(n, 1, -2))
rollapply(index, w, mean)
Edit: If you care about performance, you can use a custom Rcpp function:
library(Rcpp)
cppFunction("NumericVector fasttapermean(NumericVector x, const int window = 5) {
  const int n = x.size();
  NumericVector y(n);
  double s = x[0];
  int w = 1;
  for (int i = 0; i < n; i++) {
    y[i] = s/w;
    if (i < window/2) {
      s += x[i + (w+1)/2] + x[i + (w+3)/2];
      w += 2;
    } else if (i > n - window/2 - 2) {
      s -= x[i - (w-1)/2] + x[i - (w-3)/2];
      w -= 2;
    } else {
      s += x[i + (w+1)/2] - x[i - (w-1)/2];
    }
  }
  return y;
}")
New benchmark:
n <- 5
index <- log(seq(10, 200, by = .5))
w <- c(seq(1, n, 2), rep(n, length(index) - n - 1), seq(n, 1, -2))
bench::mark(
  fasttapermean(index),
  tapermean(index),
  zoo::rollapply(index, w, mean)
)
# # A tibble: 3 x 14
#   expression                          min     mean   median      max `itr/sec` mem_alloc  n_gc n_itr total_time result      memory              time     gc
#   <chr>                          <bch:tm> <bch:tm> <bch:tm> <bch:tm>     <dbl> <bch:byt> <dbl> <int>   <bch:tm> <list>      <list>              <list>   <list>
# 1 fasttapermean(index)              4.7us   5.94us   5.56us   67.6us  168264.     5.52KB     0 10000     59.4ms <dbl [381]> <Rprofmem [2 x 3]>  <bch:tm> <tibble [10,000 x 3]>
# 2 tapermean(index)                 53.9us  79.68us  91.08us  405.8us   12550.    37.99KB     3  5951    474.2ms <dbl [381]> <Rprofmem [16 x 3]> <bch:tm> <tibble [5,954 x 3]>
# 3 zoo::rollapply(index, w, mean)   12.8ms  15.42ms  14.31ms   29.2ms      64.9  100.58KB     8    23    354.7ms <dbl [381]> <Rprofmem [44 x 3]> <bch:tm> <tibble [31 x 3]>
However if you care about (extreme) precision you should use the rollapply method because the built-in mean algorithm of R is more accurate than the naive sum-and-divide approach.
Also note that the rollapply method is the only one that allows you to use na.rm = TRUE if needed.