函数原型中的 c++ 模板参数推导。在这种情况下可能的解决方法?

c++ template argument deduction in function prototype. possible workaround in this case?

入门

我有一个 Vector class 可以做一些数学运算。其中,它有一个 mean() 函数,可以计算向量内所有值的平均值。它使用了我在此处添加的 sum() 函数,只是为了完整性。

Vector

template <std::size_t N, typename T>
class Vector{
  public:
    
    // ...

    T sum() const {
      T ret{};
      for (const auto &item : data) {
        ret += item;
      }
      return ret;
    }

    template <typename U = T>
    U mean() const {
      return U(sum()) / N;
    }

  private:
    std::array<T,N> data;
};

mean() 函数本身有一个模板参数,因此该函数的调用者可以选择指定他想要的结果类型。例如,如果 Vector 是类型 int,如果将平均值转换为 Vector 的类型,则平均值可能会出现精度损失,在本例中为 int:

Vector<3,int> vec{2,3,5};
int mean1 = vec.mean();
int mean2 = vec.mean<int>(); // same as mean1
float mean3 = vec.mean<float>();

正如预期的那样,值为

3
3
3.333333f

这一切都很好。没问题。

问题

我遇到的问题是当我想用免费功能(在 class 之外)实现相同的功能时。我的第一个天真的实现是这样的

template <std::size_t N, class T>
T mean(const Vector<N, T> &other) {
  return other.mean();
}

但是在尝试计算 float 均值时,我必须始终调用此免费函数,同时指定模板参数 NT

Vector<3,int> vec{2,3,5};
float mean = mean<3, float>(vec);
//                ^^^i want to get rid of this "3"

问题

我知道模板参数推导在函数原型中不起作用...而且可能无法在不准确指定的情况下以某种方式推导参数 N。但也许有一个完全不相关的解决方法来消除在调用我看不到的自由函数时必须写出 N 值的需要?

I understand that template argument deduction does not work in function prototypes... And that there is likely no way of deducting the parameter N somehow without specifying it exactly.

什么?

But maybe there is a completely unrelated workaround to remove the need of having to write out the N value when calling the free function that i don't see?

下面呢?

template <typename U, std::size_t N, typename T>
U mean(const Vector<N, T> &other) {
  return other.template mean<U>();
}

你可以调用

Vector<3,int> vec{2,3,5};

mean<float>(vec);

因此推导出 3int,您只表示返回的类型 (float)。

您可以执行以下操作以获得两种语法:

template <class U, std::size_t N, typename T>
U mean(const Vector<N, T> &v) {
  return v.template mean<U>();
}

template <std::size_t N, typename T>
T mean(const Vector<N, T> &v) {
  return mean<T>(v);
}

Demo

多亏了@Jarod42 和@HTNW,我才能够把它变成一个函数。

使用 class U = voidstd::conditional 可以使 U 的规范对于调用者是可选的。

template <class U = void, std::size_t N, typename T>
auto mean(const Vector<N, T> &v) {
  return v.template mean<std::conditional_t<std::is_same_v<U, void>, T, U>>();
}

例子

Vector<3,int> v{2,3,5};
int mean1 = mean(v);          // 3
int mean2 = mean<int>(v);     // 3
float mean3 = mean<float>(v); // 3.333333f

Demo