计算通过模板传递的所有参数(非类型参数)的总和

Calculate the sum of all arguments(non-type parameters) passed through a template

我想计算通过模板传递的所有参数(非类型参数)的总和。我编译了以下程序:g++ -std=c++17 -g -Wall -o main main.cpp。似乎我错过了什么,因为我在编译时遇到了这个错误:

error: call of overloaded ‘func<N_0>()’ is ambiguous
       std::cout << func<N_0>() << std::endl;

error: call of overloaded ‘func<22>()’ is ambiguous
       return N + func<Next... >();
#include <iostream>
using namespace std;

template <std::size_t T>
std::size_t sum()
{
    return T;
}

template <std::size_t N, std::size_t ...Next>
std::size_t sum()
{
    return N + sum<Next... >();
}

int main()
{
    const size_t N_0 = 4;
    const size_t N_1 = 11;
    const size_t N_2 = 22;
    std::cout << sum<N_0>() << std::endl;
    std::cout << sum<N_0, N_1, N_2>() << std::endl;
    return 0;
}

我发现了很多这样的例子:

#include <iostream>

template<typename T>
T adder(T first) {
  return first;
}

template<typename T, typename... Args>
T adder(T first, Args... args) {
  return first + adder(args...);
}

int main() {
  const int c = adder(1, 8, 4);
  std::cout << c << '\n';
  return 0;
}

我很好奇为什么我的代码不起作用。

在第一个和第二个代码示例中,仅使用一个(模板)参数调用函数会导致两个函数模板都可行。这些包将是空的。

但是,在第二个示例的重载决策中,可变参数模板被认为不如非可变参数模板专业化,主要是因为调用它的可能参数集是非可变参数模板的超集可以调用。这只是因为函数参数中的参数包。因此,重载解析将更喜欢非可变模板作为决胜局。

此顺序不适用于您的第一个代码示例,其中两个模板的函数参数相同。

因此,使用单个(模板)参数的重载解析在您的第一个代码示例中不明确,但在第二个代码示例中不明确。


您可以指定可变参数模板至少需要两个参数来解决歧义:

template <std::size_t N, std::size_t M, std::size_t ...Next>
std::size_t sum()
{
    // May wrap-around to zero
    return N + sum<M, Next... >();
}

然而,在 C++17 及更高版本中,整个 sum 构造可以通过使用 折叠表达式 简化为:

template <std::size_t ...Ns>
std::size_t sum()
{
    // May wrap-around to zero
    return (Ns + ...);
}

(此函数可能在 C++17 中标记为 noexceptconstexpr,或者在 C++20 中标记为 consteval,并且应注意 many/large参数,因为如果总和变得太大以至于 std::size_t 无法容纳,加法将默默地回绕。)