为什么我需要默认求和函数来实现可变参数模板求和?

Adi*_*arg 0 c++ templates function-templates variadic-templates c++14

我想计算提供给 function 的任意数量的参数的总和sum。假设给予函数的整数将满足operator+.

如果我注释掉该函数sum()(没有参数的函数),则代码无法编译。如果我取消注释,代码会编译并运行,但永远不会命中 function sum()

我似乎无法理解为什么我们需要有sum()功能,因为我正在使用条件sizeof...(Args)

如果有人能帮助我理解这一点,我会非常感激吗?

/*
int sum() 
{
    std::cout << "Sum with 0 Args" << std::endl;
    return 0;
}
*/

template <typename T, typename...Args>
T sum(T first, Args...args) 
{
    // std::cout << sizeof...(Args) << std::endl;
    if (sizeof...(Args) != 0) 
    {
        return first + sum(args...);
    }
    else 
    {
        std::cout << "Found 0 args" << std::endl;
        return first;
    }
}

int main()
{
    std::cout << sum(1, 2, 3) << std::endl;
    std::cout << sum(1.2, 3.5) << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

一旦我取消注释函数 sum(),我就会得到以下输出 -

Found 0 args
6
Found 0 args
4.7
Run Code Online (Sandbox Code Playgroud)

基本上sum()永远不会被调用,这是预期的,但是为什么我们首先需要它呢?

JeJ*_*eJo 5

\n

基本上sum()永远不会被调用,这是预期的,但是为什么我们首先需要它呢?

\n
\n

当您使用普通if语句时,就像在代码中一样,两个分支都会被检查,并且两个分支都必须是可编译的。当sum递归调用时,最后一个函数调用不带参数。为了使这种情况成立,编译器需要一个sum不带参数的函数。

\n

另一方面,从开始,我们有了if constexpr,通过它我们可以在编译时只保留真正的分支。这意味着,只需按如下方式更改代码,您就不再需要sum()不带参数的了。

\n

在这里阅读更多内容:之间的区别?if constexprif

\n
template <typename T, typename...Args>\nT sum(T first, Args...args) \n{\n    if constexpr (sizeof...(Args) != 0) \n    // ^^^^^^^^^^\n    {\n       // .... as before\n    }\n    else {\n       // .... as before\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

但是,在sum中,您可以通过稍微棘手/ hacky \xe2\x80\xa0 折叠表达式来实现单个功能:

\n
#include <type_traits> // std::common_type\n\ntemplate <typename...Args>\nauto sum(Args...args) -> typename std::common_type<Args...>::type\n{\n    using unused = int[];\n    typename std::common_type<Args...>::type  total{};\n    return static_cast<void>(unused{ 0, (total += args, 0)...}), total;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在 godbolt.org 中观看现场演示

\n
\n

\xe2\x80\xa0参考文献:

\n\n