c++ - 类型检测 : using variadic arguments to properly implement a function that calculates the mean

标签 c++ c++11 templates variadic-templates template-meta-programming

我试图了解如何正确实现一个函数来计算数学样本均值,具有两个初始要求的特征:

1) 使用可变参数。

2) 不使用两个函数来完成这项工作,即不使用调用函数,然后使用第二个函数实际进行计算。

3) 函数应该尽可能通用

我很清楚已经有人问过一个非常相似的问题:Calculate the average of several values using a variadic-template function然而,虽然该问题的公认答案似乎教会了 OP 如何完成他不知道的小部分,但它提供的代码实际上是错误的并且无法编译。

所以,我自己的第一次尝试是沿着这些思路进行的:

template <class... Args>
double mean(const Args & ... args)
{
    auto total = 0;
    for (auto value : { ...args })
    {
        total += value;
    }
    return (double)total / sizeof...(args);
}

这里的问题是在 auto total = 0; 行中,编译自然无法自动识别对象 total 应该具有的类型。

然后,我的第二次尝试:

template <class T, class... Args>
T mean(const T &t, const Args & ... args)
{
    T total = 0;
    for (auto value : { args... })
    {
        total += value;
    }
    return (T)(total / sizeof...(args));
}

那个版本有以下问题。如果调用者使用混合类型的参数调用函数,它将不起作用,例如 mean(1, 2.5),其中第一个参数被自动检测为 int 并且第二个被检测为 double

我能够通过执行以下操作解决该问题:

template <class T, class... Args>
T mean(const T &t, const Args & ... args)
{
    size_t argsSize = sizeof...(args);
    T total = t;
    T arg_array[] = { args... };
    for (size_t i = 0; i< argsSize; i++)
    {
        total += (T)arg_array[i];
    }
    return (T)(total / argsSize) ;
}

即使传递的参数是不同的类型(当然,前提是这些类型可以转换为 T),这个方法仍然有效。然而,现在的问题是该函数仅适用于至少两个参数。如果像 mean(3.14) 那样调用它,虽然它应该返回 3.14,但它实际上会引发错误,因为 T arg_array[] = { args... } can'无法编译,因为不可能创建大小为 0 的静态数组。当然,我可以将其替换为动态数组,但这将使我每次调用该函数时都必须进行一次内存分配和一次内存释放 - 这是一种 Not Acceptable 浪费。

那么,实现这样一个功能的正确方法是什么,它可以避免上述问题并满足我的两个初始条件?

最佳答案

使用std::common_type_t :

template<class... Args> constexpr auto mean(Args... args) {
    std::common_type_t<Args...> total(0);
    for(auto value : {std::common_type_t<Args...>(args)...}) total += value;
    return total/sizeof...(args);
}

关于c++ - 类型检测 : using variadic arguments to properly implement a function that calculates the mean,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44404672/

相关文章:

c++ - cin.clear() 的意外行为;

c++ - 我可以将 &std::array<> 作为 void* 传递吗?

c++11 - QML如何从C++调用静态方法

c++ - 我正在尝试使用 stoi(),但编译器正在尝试给我替换并且不会编译

c++ - 定义 vs 命名空间

c++ - g++ : should --std option change which STL/stdlib my code uses?

c++ - #define - 预期和表达式 C++

c++ - 有条件地启用构造函数

wordpress - Buddypress 插件主题错误

c++ - 指定一个可以绑定(bind)到函数模板的模板参数